Re[8]: Математика и ООП: аналогии
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.11.03 16:06
Оценка:
Здравствуйте, Gaperton, Вы писали:

DG>>Императивные языки — это какие?

G>В которых ты явно прописываешь последовательность операций, "как решать задачу". В непререкаемом, повелительном (imperative) тоне . Проще говоря, процедурные языки. Прошу прощения за заумную лексику.

Smalltalk и JavaScript — тоже императивные языки, но так как они не строго типизированные, то мы можем менять тип на ходу. Т.е. если мы в какой-то момент поняли, что мы круг, то добавили себе операций, если опять эллипс, то "круговые" операции убрали.

В строготипизированные можно сделать почти тоже самое, но надо больше извращатся.
Re[9]: Математика и ООП: аналогии
От: Gaperton http://gaperton.livejournal.com
Дата: 03.11.03 16:14
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>Здравствуйте, Gaperton, Вы писали:


DG>>>Императивные языки — это какие?

G>>В которых ты явно прописываешь последовательность операций, "как решать задачу". В непререкаемом, повелительном (imperative) тоне . Проще говоря, процедурные языки. Прошу прощения за заумную лексику.

DG>Smalltalk и JavaScript — тоже императивные языки, но так как они не строго типизированные, то мы можем менять тип на ходу. Т.е. если мы в какой-то момент поняли, что мы круг, то добавили себе операций, если опять эллипс, то "круговые" операции убрали.


Ну со смаллтоком-то все что угодно может быть, это довольно странный язык. А вот с JavaScript — интересно. Не мог бы ты привести пример? Как это выглядит?

DG>В строготипизированные можно сделать почти тоже самое, но надо больше извращатся.

Это будет круто! Если можно, приведи пример для С++. Ребята заторчат.
Re[6]: Математика и ООП: аналогии
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.11.03 08:05
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Применение stretch ("сжать в n раз к большей оси") в твоем примере выведет экземпляр Circle из класса Circle, и он станет эллипсом (так как ты все-таки согласился ввести ось для круга). Если не согласен, то просто попробуй написать метод stretch.

Ну, формально говоря, все в порядке. Если мы поймем, что методов изменения состояния у нас нет, то никаких проблем не будет:
class Ellipse
{
  Ellipse Stretch(double Factor)
    {
      return new Ellipse(Focus1, Focus2, Excentricitet/Factor);
    }
}


т.е. даже если метод Stretch будет перегружен в Circle, то он все равно вернет Ellipse. В данном случае, похоже, перегрузка не понадобиться, т.к. Circle обладает всеми необходимыми свойствами для создания по ней нового эллипса. В случае других операций, например Scale, лучше будет выполнить перегрузку, чтобы возвращать именно Circle, а не Ellipse.
Но это, вообще говоря, отходит от концепций ООП, т.к. определенные таким образом объекты идентифицируются своими "значениями", а не идентичностью. Т.е. окружности с одинаковым центром и радиусами считаются тождественными. Именно это позволяет нам не напрягаться по поводу того, что возвращать из Stretch(1) — вернется другой объект, но полностью тождественный исходному, и выражение (Ellipse1.Stretch(1)==Ellipse1) будет истинным, как мы и ожидаем (в том случае, если среда позволяет правильно интерпретировать оператор == как сравнение по значению).
... << RSDN@Home 1.1 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Математика и ООП: аналогии
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 04.11.03 09:47
Оценка:
Здравствуйте, Sinclair, Вы писали:

G>>Применение stretch ("сжать в n раз к большей оси") в твоем примере выведет экземпляр Circle из класса Circle, и он станет эллипсом (так как ты все-таки согласился ввести ось для круга). Если не согласен, то просто попробуй написать метод stretch.

S>Ну, формально говоря, все в порядке. Если мы поймем, что методов изменения состояния у нас нет, то никаких проблем не будет:

Здесь проблема в другом, должно так же выполнятся следующее преобразование:
Circle circle = new Circle(new Point(0, 0), 10);
Circle circle2 = circle.Stretch(0.5).Stretch(2);
Assert.IsEqual (circle, circle2);


Есть небольшая проблема в том, что из Ellipse в некоторых случаях должен получатся Circle
Re[8]: Математика и ООП: аналогии
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.11.03 10:05
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>Здесь проблема в другом, должно так же выполнятся следующее преобразование:

DG>
DG>Circle circle = new Circle(new Point(0, 0), 10);
DG>Circle circle2 = circle.Stretch(0.5).Stretch(2);
DG>Assert.IsEqual (circle, circle2);
DG>


DG>Есть небольшая проблема в том, что из Ellipse в некоторых случаях должен получатся Circle.

Нет, так нельзя . Сигнатура Stretch запрещает нам присваивать его результат в Circle. Если мы позволим определять неявные преобразования (как в С++), то должен быть определен соответствующий оператор Ellipse -> Circle. Но надо быть готовым к тому, что он бросит исключение.
Надо отметить, что мы уже выкинули из рассмотрения всяческий аналог dynamic_cast, по тем же причинам, что и модифицирующий Stretch.
Кстати, никакой проблемы может не быть, если мы не требуем от результата нашего стретча быть именно окружностью:
Circle circle = new Circle(new Point(0, 0), 10);
Ellipse circle2 = circle.Stretch(0.5).Stretch(2); //ok
Assert.IsEqual (circle, circle2); // no problem - equality will work properly if defined on Ellipse class.
... << RSDN@Home 1.1 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Математика и ООП: аналогии
От: SG  
Дата: 04.11.03 12:30
Оценка: 6 (1)
Здравствуйте, DarkGray, Вы писали:

DG>Конечно, если мы говорит о наиболее эффективной реализации, тогда да. Есть interface IEllipse, который эллипс и круг реализуют немного по разному.


Все равно неудачно. См. вот здесь:

http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.6
Re[6]: Математика и ООП: аналогии
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 06.11.03 12:05
Оценка:
Здравствуйте, SG, Вы писали:

DG>>Конечно, если мы говорит о наиболее эффективной реализации, тогда да. Есть interface IEllipse, который эллипс и круг реализуют немного по разному.


SG> Все равно неудачно. См. вот здесь:


SG>http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.6


Есть большая разница между ООП и строготипизированным ООП.

Да, в строготипизированном ПО, для круга операции вида setRadiuses(double x, double y), stretch не удобно реализуется, потому что эти операции требует смены типа — от типа круг объект должен перейти к типу ellipse.

Но если мы рассмотриваем ООП без ограничения на строгую типизацию, то Circle может полностью реализовать интерфейс Ellipse-а
Re[7]: Математика и ООП: аналогии
От: Gaperton http://gaperton.livejournal.com
Дата: 06.11.03 12:42
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>Здравствуйте, SG, Вы писали:


DG>>>Конечно, если мы говорит о наиболее эффективной реализации, тогда да. Есть interface IEllipse, который эллипс и круг реализуют немного по разному.


SG>> Все равно неудачно. См. вот здесь:


SG>>http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.6


DG>Есть большая разница между ООП и строготипизированным ООП.


DG>Да, в строготипизированном ПО, для круга операции вида setRadiuses(double x, double y), stretch не удобно реализуется, потому что эти операции требует смены типа — от типа круг объект должен перейти к типу ellipse.


В языке С++, например, такая операция не то что "неудобно", — она не реализуется вообще. Это я вам как врач говорю. Как и в других языках со строгой типизацией. В чем проблема: допустим обявлен указатель на Circle, указывающий на наш объект. При вызове setRadiuses экземпляр класса Circle должен стать экземпляром только Ellipse. Во первых, в С++ это не возможно. Во вторых, даже если бы это было возможно, объясните что делать с указателем на Circle. И это уже безотносительно к языку.

DG>Но если мы рассмотриваем ООП без ограничения на строгую типизацию, то Circle может полностью реализовать интерфейс Ellipse-а


Любопытно. Я очень прошу Вас привести все-таки хоть один пример для JavaScript. Чертовски интересно. Потому что есть проблема. "По честному" это сделать все равно не выйдет, так как вообще говоря такая операция требует пересоздания экземпляра класса (и у вас опять "уплывут" указатели, если они не устроены как-то страшно внутри). В противном случае, пример не будет иметь отношения к ООП. Вот мне и любопытно, что-же такого может быть хитрого в казалось-бы простом языке JavaScript?

Как я уже писал, функциональные языки лишены этого недостатка (желающим посмотреть на функциональный объектно-ориентированный язык рекомендуется Haskell). Вот ТАМ — можно работать с такими объектами без проблем.
Re[7]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Gaperton http://gaperton.livejournal.com
Дата: 06.11.03 15:52
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ну, формально говоря, все в порядке. Если мы поймем, что методов изменения состояния у нас нет, то никаких проблем не будет:

S>
S>class Ellipse
S>{
S>  Ellipse Stretch(double Factor)
S>    {
S>      return new Ellipse(Focus1, Focus2, Excentricitet/Factor);
S>    }
S>}
S>


S>т.е. даже если метод Stretch будет перегружен в Circle, то он все равно вернет Ellipse. В данном случае, похоже, перегрузка не понадобиться, т.к. Circle обладает всеми необходимыми свойствами для создания по ней нового эллипса. В случае других операций, например Scale, лучше будет выполнить перегрузку, чтобы возвращать именно Circle, а не Ellipse.


Ага. Все правильно, я ждал что кто-то это придумает . Но иногда такой трюк будет выглядеть нескольно странно. Как насчет метода Ellipse::SetRadiuses( double i_x, double i_y ) из примера уважаемого SG?

S>Но это, вообще говоря, отходит от концепций ООП, т.к. определенные таким образом объекты идентифицируются своими "значениями", а не идентичностью. Т.е. окружности с одинаковым центром и радиусами считаются тождественными. Именно это позволяет нам не напрягаться по поводу того, что возвращать из Stretch(1) — вернется другой объект, но полностью тождественный исходному, и выражение (Ellipse1.Stretch(1)==Ellipse1) будет истинным, как мы и ожидаем (в том случае, если среда позволяет правильно интерпретировать оператор == как сравнение по значению).


Я бы не сказал, что это отход от концепции ООП, тем более в общем случае. В функциональных ОО языках это является нормой, так как все модифицирующие операции там запрещены в принципе (требование "прозрачности по ссылкам"). Что и приводит к тому, что объекты идентифицируются своими "значениями", а не идентичностью. Это является нормой для функциональных, и ненормальным для процедурных языков.

Здесь проблема именно в том, что мы используем процедурные языки, в которых возможность изменения состояния объектов является не просто нормой, а ключевой парадигмой, определяющей стиль разработки. Если мы не хотим проблем с нашим дизайном, необходимо отказаться от любого наследования между Circle и Ellipse, потому что:
1) существует большой класс модифицирующих операций определенных для Ellipse, которые не замкнуты на Circle (выводят Circle из класса Circle). Переводить эти операции в немодифицирующие — прием для процедурных языков исскуственный, и широкое его применение чревато серьезным усложнением системы.

2) Распространенное объяснение с другого конца (например, в ссылке приведенной SG): нарушается "принцип подстановки Лисков". Он состоит в том, что экземпляр подкласса должен быть пригоден к использованию во всех контекстах, где может быть использован базовый класс. К кругу нельзя сделать операцию SetFocuses. На самом деле здесь тоже неявно предполагается, что операция обязана быть замкнутой. Просто акценты стоят по другому.
Re[8]: Математика и ООП: аналогии
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 07.11.03 21:03
Оценка: 6 (1)
Здравствуйте, Gaperton, Вы писали:


G>Любопытно. Я очень прошу Вас привести все-таки хоть один пример для JavaScript. Чертовски интересно. Потому что есть проблема. "По честному" это сделать все равно не выйдет, так как вообще говоря такая операция требует пересоздания экземпляра класса (и у вас опять "уплывут" указатели, если они не устроены как-то страшно внутри). В противном случае, пример не будет иметь отношения к ООП. Вот мне и любопытно, что-же такого может быть хитрого в казалось-бы простом языке JavaScript?


В простом языке JavaScript мы можем к объекту добавлять, удалять функции на лету, в отличии от строго типизированных языков:

Будет что-то такое:
function CreateEllipse(focus1, focus2, diameter)
{
  var ellipse = new object();
  ellipse.UpdateFigure = UpdateFigure;
  ellipse.Stretch = Stretch;
  ellipse.focus1 = focus1;
  ellipse.focus2 = focus2;
  ellipse.diameter = diameter;
  return ellipse;
}

function CreateCircle(center, radius)
{
  var circle = CreateEllipse(center, center, radius * 2);
  circle.UpdateFigure();
  return circle;
}

function Stretch(int k)
{
  this.ChangeFocusesAndDiameter(k);

  this.UpdateFigure();
}


function SetCenter(center)
{
  this.focus1 = center;
  this.focus2 = center;
}
function GetCenter()
{
  return this.focus1;
}


function UpdateFigure()
{
  if (this.IsCircle())
    Ellipse2Circle(this);
  else
    Circle2Ellipse(this);
}

function IsCircle()
{
  return this.focus1 == this.focus2;
}

function Ellipse2Circle(ellipse)
{
  ellipse.SetCenter = SetCenter;
  ellipse.GetCenter = GetCenter;
}

function Circle2Ellipse(ellipse)
{
  ellipse.SetCenter = null;
  ellipse.GetCenter = null;
}
Re[8]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 07.11.03 22:15
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Ага. Все правильно, я ждал что кто-то это придумает . Но иногда такой трюк будет выглядеть нескольно странно. Как насчет метода Ellipse::SetRadiuses( double i_x, double i_y ) из примера уважаемого SG?


Что-нибудь такое
using System;
using System.Drawing;

namespace ConsoleApplication1
{
    public interface IEllipse
    {
        void SetFocuses(PointF focus1, PointF focus2);
        PointF Focus1{get;set;}
        PointF Focus2{get;set;}
        void StretchByBigAxis(double k);
    }

    public interface ICircle:
        IEllipse
    {
        PointF Center {get;set;}
    }

    public abstract class EllipseWrapper:
        IEllipse
    {
        protected abstract IEllipse InnerEllipse {get;}
    
        #region IEllipse Members

        public void SetFocuses(PointF focus1, PointF focus2)
        {
            InnerEllipse.SetFocuses(focus1, focus2);
        }

        public void StretchByBigAxis(double k)
        {
            InnerEllipse.Stretch(k);
        }

        public PointF Focus1
        {
            get {return InnerEllipse.Focus1;}
            set {InnerEllipse.Focus1 = value;}
        }

        public PointF Focus2
        {
            get {return InnerEllipse.Focus2;}
            set {InnerEllipse.Focus2 = value;}
        }

        #endregion
    }
    public abstract class CircleWrapper:
        EllipseWrapper,
        ICircle
    {
        protected abstract ICircle InnerCircle {get;}

        protected override IEllipse InnerEllipse
        {
            get
            {
                return InnerCircle;
            }
        }


    
        #region ICircle Members

        public PointF Center
        {
            get
            {
                return InnerCircle.Center;
            }
            set
            {
                InnerCircle.Center = value;
            }
        }

        #endregion
    }

    public class CircleImpl:
        EllipseWrapper,
        ICircle
    {
        public CircleImpl(IEllipse ellipse)
        {
            this._InnerEllipse = ellipse;
        }
        IEllipse _InnerEllipse;
        protected override IEllipse InnerEllipse
        {
            get
            {
                return _InnerEllipse;
            }
        }

    
            #region ICircle Members

            public PointF Center
            {
                get
                {
                    return InnerEllipse.Focus1;
                }
                set
                {
                    InnerEllipse.Focus1 = InnerEllipse.Focus2 = value;
                }
            }

            #endregion
        }

    public class Ellipse:
        IEllipse
    {
        public Ellipse(PointF focus1, PointF focus2)
        {
            this._Focus1 = focus1;
            this._Focus2 = focus2;
        }
    
        #region IEllipse Members

        PointF _Focus1, _Focus2;
        public void SetFocuses(PointF focus1, PointF focus2)
        {
            this.Focus1 = focus1;
            this.Focus2 = focus2;
        }

        public PointF Focus1
        {
            get
            {
                return _Focus1;
            }
            set
            {
                _Focus1 = value;
            }
        }

        public PointF Focus2
        {
            get
            {
                return _Focus2;
            }
            set
            {
                _Focus2 = value;
            }
        }

        public void StretchByBigAxis(double k)
        {
        }

        #endregion
    }

    public class Circle:
        CircleWrapper
    {
        public Circle(IEllipse ellipse)
        {
            _InnerCircle = new CircleImpl(ellipse);            
        }
        ICircle _InnerCircle;
        protected override ICircle InnerCircle
        {
            get
            {
                if (!IsCircle(_InnerCircle))
                    throw new Exception("Данная фигура не круг");
                return _InnerCircle;
            }
        }


        public static ICircle AsCircle(IEllipse ellipse)
        {
            if (!IsCircle(ellipse))
                throw new Exception("Данная фигура не круг");
            if (ellipse is ICircle)
                return (ICircle)ellipse;
            return new Circle(ellipse);
        }
        public static bool IsCircle(IEllipse ellipse)
        {
            return ellipse.Focus1 == ellipse.Focus2;
        }
    }


    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    class Class1
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            IEllipse ellipse = new Ellipse(new PointF(0, 1), new PointF(0, -1));
            ellipse.SetFocuses(new PointF(0, 0), new PointF(0, 0));
            ICircle circle = Circle.AsCircle(ellipse);
            circle.StretchByBigAxis(1.5);
        }
    }
}
Re[9]: Математика и ООП: аналогии
От: Gaperton http://gaperton.livejournal.com
Дата: 08.11.03 15:23
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>В простом языке JavaScript мы можем к объекту добавлять, удалять функции на лету, в отличии от строго типизированных языков:


Спасибо, все понял!

1) Язык полиморфный.

2) Закрыть данные нельзя, верно? Т. е. инкапсуляция языком не поддерживается. Все так?

3) Типы конструируются динамически и определяются неявно. Применяется позднее связывание. Поэтому нет необходимости в наследовании. Вернее, поведение аналогичное наследованию организовать можно, но при этом в понятии "наследование" нет необходимости. По выразительной силе похоже на шаблоны C++, но еще мощнее, так как работает во время исполнения.

В общем, согласен, в JavaScript такой проблемы нет. Одна проблема
Язычок прикольный, но вроде как по любому не объектно-ориентированный . Формально из 3 признаков ОО языка в наличии 1. Неформально — концепция JavaScript превосходит по гибкости ООП.
Re[9]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Gaperton http://gaperton.livejournal.com
Дата: 08.11.03 16:38
Оценка: 2 (2) +1 :)
Здравствуйте, DarkGray, Вы писали:

DG>Здравствуйте, Gaperton, Вы писали:


G>>Ага. Все правильно, я ждал что кто-то это придумает . Но иногда такой трюк будет выглядеть нескольно странно. Как насчет метода Ellipse::SetRadiuses( double i_x, double i_y ) из примера уважаемого SG?


DG>Что-нибудь такое

Я в шоке, дорогая редакция Добро пожаловать в мир занимательного си-шарпа
2 интерфейса, 5 классов (не считая точки) — 7 разных типов данных.

Самый интересный вопрос, которым задасца читатель с пытливым умом, это что-же все-таки на самом деле случится с Circle в вашем примере после применения операции StretchByBigAxis? Это сложно понять, и поэтому, браццы, видимо придецца верить мне на слово : Он как был на самом деле эллипсом, так им и остался . Не верицца — почитайте КОД.

Можно было еще проще:

class Ellipse : ICircle, IEllipse;

И фсе, собственно. Тот же известный анатомический орган, только вид сбоку. Высеченная в коде как на граните констатация простого факта, что круг это частный случай эллипса.

Вса-таки, позвольте поинтересоваться: что именно хотели вы приллюстрировать этим примером? К сожалению, у меня не хватает моральных сил до конца разобраться в КОДЕ, так как он почему-то выводит меня из душевного равновесия, мягко выражаясь . Ничего личного, это мои проблемы.
Re[10]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 30.04.04 16:55
Оценка:
G>>>Ага. Все правильно, я ждал что кто-то это придумает . Но иногда такой трюк будет выглядеть нескольно странно. Как насчет метода Ellipse::SetRadiuses( double i_x, double i_y ) из примера уважаемого SG?

DG>>Что-нибудь такое

G>Я в шоке, дорогая редакция Добро пожаловать в мир занимательного си-шарпа
G>2 интерфейса, 5 классов (не считая точки) — 7 разных типов данных.

Типов четыре — два интерфейса и две реализации. Все остальное — это издержки C#, т.к. C# — низкоуровневый язык. Фактически остальные три класса — это смарт-поинтеры.


— Теперь о ситуации в общем. —

Наследование бывает разным: бывает наследование расширающее, бывает наследование сужающее, в первом случае — мы к предку добавляем новые возможности, во втором случае — мы к предку добавляет новые ограничения.

Пример:
рассмотрим интервальные типы,
в частности — тип, значения которого определены на интервале 1..1000.

Данный тип — наследует всю функциональность целого типа с учетом ограничений. К данному типу применимы большинство операций, свойств, теорем целого типа за небольшим исключением.
Но в то же время операция: верни число со знаком минус является бессмысленной, и можно даже сказать неприменимой к данному типу.


Другой пример:
рассмотрим шизофреника (человека с раздвоением личности)
С одной стороны, доступны все те же операции, что и над обычным человек, с другой стороны, такая тривиальная операция, как "Скажи свое имя" шизофреника загонит в ступор, т.к. сразу появляется вопросы: Какое из имен?, Первой личности? Второй? Любое? А кто спрашивает?

Получается, что и для случая расширающего наследования, и для сужающего — мы не можем напрямую поддерживать все операции, который были доступны для предка.

Проблема в том, что языки со статической типизацией (C++, C#, Java) не только не решают данную проблему, но даже не дают ни одной возможности решить эту проблему в своих рамках.
Re[11]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Gaperton http://gaperton.livejournal.com
Дата: 30.04.04 17:50
Оценка: 1 (1) +1
Здравствуйте, DarkGray, Вы писали:

DG>Наследование бывает разным: бывает наследование расширающее, бывает наследование сужающее, в первом случае — мы к предку добавляем новые возможности, во втором случае — мы к предку добавляет новые ограничения.


Наследование это не отношение "подмножество". Говоря об типах в ООП мы обязаны принять во внимание, что [абстрактный] тип данных (класс) определяется только операциями над ним. При правильном применении наследования в любых языках должен соблюдаться "принцип подстановки Лисков", который состоит в том, что "подкласс должен быть пригоден к использованию во всех контекстах, что и базовый класс", что означает, что операции в подклассе должны работать и сохранять семантику.
Другими словами, "сужающее" наследование — совершенно некорректная штука.
Re[12]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 07:35
Оценка:
DG>>Наследование бывает разным: бывает наследование расширающее, бывает наследование сужающее, в первом случае — мы к предку добавляем новые возможности, во втором случае — мы к предку добавляет новые ограничения.

G>Наследование это не отношение "подмножество". Говоря об типах в ООП мы обязаны принять во внимание, что [абстрактный] тип данных (класс) определяется только операциями над ним. При правильном применении наследования в любых языках должен соблюдаться "принцип подстановки Лисков", который состоит в том, что "подкласс должен быть пригоден к использованию во всех контекстах, что и базовый класс", что означает, что операции в подклассе должны работать и сохранять семантику.

G>Другими словами, "сужающее" наследование — совершенно некорректная штука.

В каких отношениях тогда находится тип целое числа и тип натуральное число?

Между ними можно провести отношение наследования или это совсем разные типы, между которыми ничего общего?

Т.е. получается, что мы должны отдельно завести тип целое число, определить для него операции, потом отдельно завести тип натуральное число опять определив все операции?
Потом также отдельно завести типы [0..10), [-4..1000], [0..255], [0..65535] и т.д.?




ps
Лисков, наверное, жил в идеальном мире, где есть только черное и белое, а мы живем в реальном мире, в котором поддержка только части исходного интерфейса — это норма.
Re[13]: Задачка про Circle/Ellipse: "официальный" ответ.
От: INTP_mihoshi Россия  
Дата: 05.05.04 08:50
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>>>Наследование бывает разным: бывает наследование расширающее, бывает наследование сужающее, в первом случае — мы к предку добавляем новые возможности, во втором случае — мы к предку добавляет новые ограничения.


G>>Наследование это не отношение "подмножество". Говоря об типах в ООП мы обязаны принять во внимание, что [абстрактный] тип данных (класс) определяется только операциями над ним. При правильном применении наследования в любых языках должен соблюдаться "принцип подстановки Лисков", который состоит в том, что "подкласс должен быть пригоден к использованию во всех контекстах, что и базовый класс", что означает, что операции в подклассе должны работать и сохранять семантику.

G>>Другими словами, "сужающее" наследование — совершенно некорректная штука.

Кстати, конструкторы являются частью интерфейса?

DG>В каких отношениях тогда находится тип целое числа и тип натуральное число?

Если все методы константны — то вполне могут быть Лисковыми классом и подклассом. Различаются только конструкторы.

DG>Между ними можно провести отношение наследования или это совсем разные типы, между которыми ничего общего?

Скорее так: между наследованием и типами нет ничего общего. Ну, или почти ничего. Наследование — не единственный способ связи.

DG>ps

DG>Лисков, наверное, жил в идеальном мире, где есть только черное и белое, а мы живем в реальном мире, в котором поддержка только части исходного интерфейса — это норма.
Просто он, видимо, не имел в виду С++...
С С++ можно работать по искову, но для этого надо полностью использовать множественное наследование и идентификаторы доступа (private etc.)
Кстати, интерфейс нельзя поддерживать частично. Либо поддерживаешь, либо нет.
Re[13]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Reyst Россия  
Дата: 05.05.04 09:15
Оценка:
Здравствуйте, DarkGray, Вы писали:
DG>Лисков, наверное, жил в идеальном мире

Жила. Она все-таки Барбара...
Все, что здесь сказано, может и будет использоваться против меня...
Re[13]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.05.04 10:35
Оценка: 5 (2) +1
Здравствуйте, DarkGray, Вы писали:
DG>Между ними можно провести отношение наследования или это совсем разные типы, между которыми ничего общего?
Смешно. Ни то ни другое. Наследованием не исчерпываются взаимоотношения между типами.
Можно было бы ввести метаинтерфейс, который содержит все нужные нам мат.операции. Мета — потому, что мы не можем фиксировать тип параметров. Можем только потребовать, чтобы operator + (type, type) возвращал снова type, а не хрен собачий.
В итоге мы бы получили два типа, которые реализуют эти операции. Вот только целые числа умели бы еще немножко больше. И у нас был бы оператор преобразования, который позволяет получать по любому натуральному числу его целый аналог. Обратного оператора быть не должно.
Я бы хотел подчеркнуть, что в такой модели есть два разных объекта "2" — целая двойка и натуральная двойка. У натуральной двойки нет оператора унарного минуса. Поэтому вычитание из 4 2 выглядит примерно так: Integer(Natural(4))+Negation(Integer(Natural(2))).

DG>Т.е. получается, что мы должны отдельно завести тип целое число, определить для него операции, потом отдельно завести тип натуральное число опять определив все операции?

DG>Потом также отдельно завести типы [0..10), [-4..1000], [0..255], [0..65535] и т.д.?

DG>Лисков, наверное, жил в идеальном мире, где есть только черное и белое, а мы живем в реальном мире, в котором поддержка только части исходного интерфейса — это норма.

Барбара вообще ничего не говорила про числа. Ребята, математика — хреновое поле приложения ООП. Она базируется на теории множеств. В отличие от объектов, элементы множества суть вечные и неизменные э-э... элементы, и поведением (которое суть неотъемлемая часть парадигмы ООП) не обладают. Поэтому для них стоит придумать отдельную теорию. Хотя некоторые аспекты их функциональности и можно с различным успехом смоделировать в ООП.
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 10:49
Оценка:
INT>Кстати, конструкторы являются частью интерфейса?

Если рассматривать ООП, в общем виде, то — да, является, но в нынешних языках — формально мы это специфировать не можем.


DG>>В каких отношениях тогда находится тип целое числа и тип натуральное число?

INT>Если все методы константны — то вполне могут быть Лисковыми классом и подклассом. Различаются только конструкторы.

В данном случае, подкласс в смысле наследник? или в каком смысле "под"?


DG>>Между ними можно провести отношение наследования или это совсем разные типы, между которыми ничего общего?

INT>Скорее так: между наследованием и типами нет ничего общего. Ну, или почти ничего. Наследование — не единственный способ связи.

Какое отношение в данном случае есть?

DG>>ps

DG>>Лисков, наверное, жил в идеальном мире, где есть только черное и белое, а мы живем в реальном мире, в котором поддержка только части исходного интерфейса — это норма.
INT>Просто он, видимо, не имел в виду С++...
INT>С С++ можно работать по искову, но для этого надо полностью использовать множественное наследование и идентификаторы доступа (private etc.)

INT>Кстати, интерфейс нельзя поддерживать частично. Либо поддерживаешь, либо нет.


Ха! Открой спецификацию любого сложный интерфейс. Почти всегда большая часть методов является опциональными, т.е. получается, что на уровне метаданных метод есть, но реально его нет. Реально он не поддерживается.
Т.е. даже на уровне спецификаций многие интерфейсы можно поддерживать частично. Что же тогда творится на самом деле.

ps
Взять те же компиляторы C++. Есть строго специфицированный стандарт C++, фактически это интерфейс взаимодействия между текстом и результатом в виде программы. И насколько много компиляторов, которые поддерживают полностью данный интерфейс(стандарт)?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.