Кто автор?
От: gbear Россия  
Дата: 21.07.05 13:12
Оценка:
День добрый...

Сорри, за возможный оффтоп, но вряд ли кто-либо кроме участников этого форума знает ответ.

Вопрос такой... Никто не в курсе, кто автор задачки "про квадрат и прямоугольник" (что-то типа):

Дано две сущности: квадрат и прямоугольник. Они обладают следующим поведением:

1. Предоставляют информацию о своих размерах.
2. Могут изменять свои размеры.
3. Предоставляют информацию о своей площади.

Вопрос: Кто из них родитель, а кто предок? Почему?


Я всегда считал, что в свое время "подсмотрел" её у Буча... Но вот что-то сегодня полистал его — ничего похожего не нашёл. Но, блин, вряд ли я её сам придумал

---
С уважением, Сиваков Константин
Re: Кто автор?
От: LtrK2  
Дата: 21.07.05 13:28
Оценка:
Здравствуйте, gbear, Вы писали:

G>День добрый...


G>Сорри, за возможный оффтоп, но вряд ли кто-либо кроме участников этого форума знает ответ.


G>Вопрос такой... Никто не в курсе, кто автор задачки "про квадрат и прямоугольник" (что-то типа):


G>Дано две сущности: квадрат и прямоугольник. Они обладают следующим поведением:


G>1. Предоставляют информацию о своих размерах.

G>2. Могут изменять свои размеры.
G>3. Предоставляют информацию о своей площади.

G>Вопрос: Кто из них родитель, а кто предок? Почему?


G>Я всегда считал, что в свое время "подсмотрел" её у Буча... Но вот что-то сегодня полистал его — ничего похожего не нашёл. Но, блин, вряд ли я её сам придумал


G>---

G>С уважением, Сиваков Константин

Я не в курсе, увы. И задачу вижу в первый раз.
Считаю, что правильный ответ: родитель — квадрат.
Можно узнать правильный ответ?
Re: Кто автор?
От: dshe  
Дата: 21.07.05 13:36
Оценка: 6 (1) +3
Здравствуйте, gbear, Вы писали:

G>День добрый...


G>Сорри, за возможный оффтоп, но вряд ли кто-либо кроме участников этого форума знает ответ.


G>Вопрос такой... Никто не в курсе, кто автор задачки "про квадрат и прямоугольник" (что-то типа):


G>Дано две сущности: квадрат и прямоугольник. Они обладают следующим поведением:


G>1. Предоставляют информацию о своих размерах.

G>2. Могут изменять свои размеры.
G>3. Предоставляют информацию о своей площади.

G>Вопрос: Кто из них родитель, а кто предок? Почему?


G>Я всегда считал, что в свое время "подсмотрел" её у Буча... Но вот что-то сегодня полистал его — ничего похожего не нашёл. Но, блин, вряд ли я её сам придумал


Может
The Liskov Substitution Principle
Robert C. Martin
C++ Report, 1996
http://www.objectmentor.com/resources/articles/lsp.pdf
--
Дмитро
Re[2]: Кто автор?
От: Курилка Россия http://kirya.narod.ru/
Дата: 21.07.05 13:38
Оценка: 6 (1) +2
Здравствуйте, LtrK2, Вы писали:

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

...

LK>Я не в курсе, увы. И задачу вижу в первый раз.

LK>Считаю, что правильный ответ: родитель — квадрат.
LK>Можно узнать правильный ответ?

Почему квадрат?
Вообще ни квадрат ни прямоугольник с т. зр. ООП, т.к. полиморфизм нарушается, единственное мы можем вынести общий интерфейс, но в каждом классе будут частные вещи, которых нет в другом (или поедение оных будет отличным == нарушение полиморфизма, принципа Лисков).
Re: Кто автор?
От: mibe  
Дата: 21.07.05 14:23
Оценка: 6 (1)
Здравствуйте, gbear, Вы писали:

G>Вопрос: Кто из них родитель, а кто предок? Почему?[/i]


В данном случае названия неудачные, т.к. в определение квадрата не входит инвариант
ширина=высота. Поэтому не все квадраты в описанном случае будут являтся квадратами с точки зрения геометрии.

С другой стороны, можно сами названия Квадрат и Прямоугольник рассматривать как отсылку к математике и неявной декларацией подобных инвариантов.

А еще бывают языки типа cecil где класс можно декларативно определить (типа квадрат это прямоугольник у которого длина=ширина) и конкретный объект классифицируется динамически на основе такого определения.
--
Far.Net
Re[2]: Кто автор?
От: cranky Украина  
Дата: 21.07.05 14:47
Оценка: +1
Здравствуйте, LtrK2, Вы писали:

LK>Считаю, что правильный ответ: родитель — квадрат.


скорее прямоугольник, у него ширина и высота, а квадрат — это уже его специализация, где w==h
You aren't expected to absorb this
Re[2]: Кто автор?
От: gbear Россия  
Дата: 22.07.05 04:40
Оценка:
Здравствуйте, LtrK2, Вы писали:

LK>Я не в курсе, увы. И задачу вижу в первый раз.


Жаль

LK>Считаю, что правильный ответ: родитель — квадрат.


Главный-то вопрос объяснить почему

LK>Можно узнать правильный ответ?


Вообще говоря — его как бы и нет Есть теоритически правильный ответ, базирующийся на том утверждении, что сущности обладающие подобным поведением (не в смысле таким... а в смысле, что поведения этих сущностей подобны) лежат на одном уровне иерархии классов.
В реальности это не всегда так.

---
С уважением, Сиваков Константин.
Re[3]: Кто автор?
От: gbear Россия  
Дата: 22.07.05 04:44
Оценка: +1
Здравствуйте, Курилка, Вы писали:

К>Вообще ни квадрат ни прямоугольник с т. зр. ООП, т.к. полиморфизм нарушается


Ээээ... По поводу нарущения полиморфизма можно по подробнее. Такое возражение слушу в первые.

---
С уважением, Сиваков Константин.
Re[3]: Кто автор?
От: mihoshi Россия  
Дата: 22.07.05 05:15
Оценка: 1 (1) +1
Здравствуйте, cranky, Вы писали:

LK>>Считаю, что правильный ответ: родитель — квадрат.


C>скорее прямоугольник, у него ширина и высота, а квадрат — это уже его специализация, где w==h


А если рассмотреть целые и действительный числа — что из них родитель, а что предок?
Re[2]: Кто автор?
От: gbear Россия  
Дата: 22.07.05 05:16
Оценка:
Здравствуйте, dshe, Вы писали:

D>Может

D>The Liskov Substitution Principle
D>Robert C. Martin
D>C++ Report, 1996
D>http://www.objectmentor.com/resources/articles/lsp.pdf

Неа... Он подходит к этому вопросу (да и вопрос-то, вообще говоря не совсем тот ) с точки зрения конкретной реализации поведения. А данный вопрос, вообще говоря, "разрешим" на уровне "чистых сущностей" — и не имеет к контретным реализациям их поведения никакого отношения. Тем более — или мне показалось? — он совсем не рассмотрел в этой работе вариант S<-R что ооочень странно.

Кароче, не то это... Хотя, действительно, похоже...

---
С уважением, Сиваков Константин.
Re[3]: Кто автор?
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 22.07.05 07:06
Оценка:
G>Здравствуйте, dshe, Вы писали:

D>>Может

D>>The Liskov Substitution Principle
D>>Robert C. Martin
D>>C++ Report, 1996
D>>http://www.objectmentor.com/resources/articles/lsp.pdf

G>Неа... Он подходит к этому вопросу (да и вопрос-то, вообще говоря не совсем тот ) с точки зрения конкретной реализации поведения. А данный вопрос, вообще говоря, "разрешим" на уровне "чистых сущностей" — и не имеет к контретным реализациям их поведения никакого отношения. Тем более — или мне показалось? — он совсем не рассмотрел в этой работе вариант S<-R что ооочень странно.


G>Кароче, не то это... Хотя, действительно, похоже...


Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.
А на уровне "чистых сущностей" иерархии не будет вообще.
... << RSDN@Home 1.1.4 stable rev. 510>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[4]: Кто автор?
От: Курилка Россия http://kirya.narod.ru/
Дата: 22.07.05 07:55
Оценка:
Здравствуйте, gbear, Вы писали:

G>Здравствуйте, Курилка, Вы писали:


К>>Вообще ни квадрат ни прямоугольник с т. зр. ООП, т.к. полиморфизм нарушается


G>Ээээ... По поводу нарущения полиморфизма можно по подробнее. Такое возражение слушу в первые.


Да всё просто у тебя есть ширина и длина, так?
Берём за предка квадрат, тогда ширина==длина и изменение одной влечёт за собой изменение другой, наследуем от него прямоугольник, НО ширина!=длина, т.е. поведение объекта совпадает с поведением предка, ну нельзя сказать что любой прямоугольник есть квадрат => нарушение LSP.
Если берём обратный вариант (и более естественный с т.зр. геометрии), то получаем неожиданное поведение у квадрата (если рассматривать его абстрактно как прямоугольник): изменение ширины вдруг магическим образом должно вызывать изменение длины и наоборот, т.е. поведение квадрата будет отличаться от поведения прямоугольника (точнее будут отличаться следствия функций-аксессоров для длины/ширины). Нарушение меньшее чем в 1-м случае, но всё равно чреватое...
(E.g. мы сохранили длину прямоугольника, который квадрат на самом деле, потом поменяли ширину и в сохранённом значении длины у нас уже "левое" значение)
Re[4]: Кто автор?
От: Курилка Россия http://kirya.narod.ru/
Дата: 22.07.05 07:57
Оценка:
Здравствуйте, mihoshi, Вы писали:

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


LK>>>Считаю, что правильный ответ: родитель — квадрат.


C>>скорее прямоугольник, у него ширина и высота, а квадрат — это уже его специализация, где w==h


M>А если рассмотреть целые и действительный числа — что из них родитель, а что предок?


Твоя версия?
Re[4]: Кто автор?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 22.07.05 08:08
Оценка: +1
Здравствуйте, Andrei N.Sobchuck, Вы писали:

ANS>Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.


По-моему, фамилия Лисков не склоняется. По крайней мере везде в русскоязычной литературе было написано "принцип Лисков (Барбара Лисков)", а не "принцип Лисковой"
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Кто автор?
От: cranky Украина  
Дата: 22.07.05 08:42
Оценка: +2
Здравствуйте, mihoshi, Вы писали:

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


LK>>>Считаю, что правильный ответ: родитель — квадрат.


C>>скорее прямоугольник, у него ширина и высота, а квадрат — это уже его специализация, где w==h


M>А если рассмотреть целые и действительный числа — что из них родитель, а что предок?


Думается, что у них просто общий абстрактный предок (или интерфейс), определяющий общие операции.
You aren't expected to absorb this
Re[5]: Кто автор?
От: gbear Россия  
Дата: 22.07.05 08:54
Оценка:
Здравствуйте, Курилка, Вы писали:

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


К>Да всё просто у тебя есть ширина и длина, так?


Вообще-то нет Есть длины сторон. Квадрат задается одной такой длиной. Прямоугольник двумя... Но, походу, не суть.

К>Берём за предка квадрат, тогда ширина==длина и изменение одной влечёт за собой изменение другой, наследуем от него прямоугольник, НО ширина!=длина, т.е. поведение объекта совпадает с поведением предка, ну нельзя сказать что любой прямоугольник есть квадрат => нарушение LSP.


Да не факт, собственно. Ну будет агрегат работать с прямоугольником как с квадратом... Тут уже все уперается в особенности реализации "ф-ции" изменения размеров. Её ведь и так можно написать, что если с прямоугольником работать как с квадратом — задавая его длиной одной стороны — то он "превратиться" в "квадрат". Так что, повторюсь, для меня например весьма странно было, что в том документе, где приведена похожая задача не рассмотрен вариант S<-R.

К>Если берём обратный вариант (и более естественный с т.зр. геометрии), то получаем неожиданное поведение у квадрата (если рассматривать его абстрактно как прямоугольник): изменение ширины вдруг магическим образом должно вызывать изменение длины и наоборот, т.е. поведение квадрата будет отличаться от поведения прямоугольника (точнее будут отличаться следствия функций-аксессоров для длины/ширины). Нарушение меньшее чем в 1-м случае, но всё равно чреватое...


ИМХО, тут-то как раз нарушения безусловно есть — в варианте S<-R их можно избежать.

---
С уважением, Сиваков Константин.
Re[4]: Кто автор?
От: gbear Россия  
Дата: 22.07.05 09:07
Оценка:
Здравствуйте, Andrei N.Sobchuck, Вы писали:

G>>Кароче, не то это... Хотя, действительно, похоже...


ANS>Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.


Да не то... Именно потому, что автор уже оперирует сигнатурами методов и т.п. Т.е. работает с конкретной реализацией. Та же "задача", которую я имею ввиду — ставилась на этапе анализа предметной области. Т.е. мы только выявили что у нас будет две сущности... и т.д. Мы ещё не задумываемся над тем как именно будет реализовываться поведение... нет у нас сигнатур.

ANS>А на уровне "чистых сущностей" иерархии не будет вообще.


Угу... Зато на уровне "чистых сущностей" уже можно оценить какие отношения будут между классами, реализующие данные сущности. Собственно, практическая ценность, если можно так выразиться, данного вопроса — суть, выявление "интерфейсных" сущностей уже на этапе анализе предметной области — как известно, на этом этапе, просто так их не выявить.

---
С уважением, Сиваков Константин.
Re[6]: Кто автор?
От: Курилка Россия http://kirya.narod.ru/
Дата: 22.07.05 09:13
Оценка:
Здравствуйте, gbear, Вы писали:

G>Здравствуйте, Курилка, Вы писали:


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


К>>Да всё просто у тебя есть ширина и длина, так?


G>Вообще-то нет Есть длины сторон. Квадрат задается одной такой длиной. Прямоугольник двумя... Но, походу, не суть.


К>>Берём за предка квадрат, тогда ширина==длина и изменение одной влечёт за собой изменение другой, наследуем от него прямоугольник, НО ширина!=длина, т.е. поведение объекта совпадает с поведением предка, ну нельзя сказать что любой прямоугольник есть квадрат => нарушение LSP.


G>Да не факт, собственно. Ну будет агрегат работать с прямоугольником как с квадратом... Тут уже все уперается в особенности реализации "ф-ции" изменения размеров. Её ведь и так можно написать, что если с прямоугольником работать как с квадратом — задавая его длиной одной стороны — то он "превратиться" в "квадрат". Так что, повторюсь, для меня например весьма странно было, что в том документе, где приведена похожая задача не рассмотрен вариант S<-R.


Вот код:

class S
{
 int side_;
 virtual int Width
 {
  get
  {
   return side_;
  }
 }
 virtual int Height
 {
  get
  {
   return Width;
  }
 }
}

class R:S
{
 int height_;
 int width_;
 override int Width
 {
  get
  {
   return width__;
  }
 }
 override int Height
 {
  get
  {
   return height_;
  }
 }
}


Это то, что ты имеешь в виду? Если да, то это просто явная бага в логике — ну не нужно нам для КВАДРАТА иметь длину и ширину, т.к. нам нужна только сторона и площадь мы будем получать квадратом её, а никак не произведением сторон. Т.е. получаем, что твой "квадрат" описывает больше того, что он должен описывать, т.е. для пользователя становится нужным знание, что от квадрата может унаследоваться прямоугольник, поэтому нужны 2 стороны. Имхо с т.зр. логики это просто бред. Может ты ещё и число сторон включишь и массив их длин и углов, дабы вообще произвольный многоугольник описывать?
Re[6]: Кто автор?
От: Курилка Россия http://kirya.narod.ru/
Дата: 22.07.05 09:19
Оценка:
Здравствуйте, gbear, Вы писали:

G>Здравствуйте, Курилка, Вы писали:


К>>Если берём обратный вариант (и более естественный с т.зр. геометрии), то получаем неожиданное поведение у квадрата (если рассматривать его абстрактно как прямоугольник): изменение ширины вдруг магическим образом должно вызывать изменение длины и наоборот, т.е. поведение квадрата будет отличаться от поведения прямоугольника (точнее будут отличаться следствия функций-аксессоров для длины/ширины). Нарушение меньшее чем в 1-м случае, но всё равно чреватое...


G>ИМХО, тут-то как раз нарушения безусловно есть — в варианте S<-R их можно избежать.


Кстати — какие тут нарушения ты видишь?
Re[7]: Кто автор?
От: gbear Россия  
Дата: 22.07.05 09:52
Оценка: -1
Здравствуйте, Курилка, Вы писали:

К>Вот код:


<Код поскипан>

К>Это то, что ты имеешь в виду?


Нет... Я имею ввиду, что-то типа этого:
    class S
    {
        private int _size;
        public virtual int Size
        {
            get
            {
                return _size;
            }
            set
            {
                _size = value;
            }
        }
    }

    class R : S
    {
        private int _size;
        
        public int Height
        {
            get
            {
                return base.Size;
            }
            set
            {
                base.Size = value;
            }
        }

        public int Width
        {
            get
            {
                return this._size;
            }
            set
            {
                this._size = value;
            }
        }

        public override int Size
        {
            get
            {
                return base.Size;
            }
            set
            {
                base.Size = value;
                this._size = value;
            }
        }
    }



Реализация R.get_Size может быть различной.... такой какой нам нужно будет — вплоть до вызова R.set_Size(base.Size) перед ретурном. Не суть...

---
С уважением, Сиваков Константин
Re[7]: Кто автор?
От: gbear Россия  
Дата: 22.07.05 09:57
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Кстати — какие тут нарушения ты видишь?


По сути одно... В контракте квадрата будет "лишняя" функциональность унаследованная от прямоугольника (работа со вторым размером).

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

---
С уважением, Сиваков Константин.
Re[8]: Кто автор?
От: Курилка Россия http://kirya.narod.ru/
Дата: 22.07.05 10:02
Оценка:
Здравствуйте, gbear, Вы писали:


G><Код поскипан>


G>Реализация R.get_Size может быть различной.... такой какой нам нужно будет — вплоть до вызова R.set_Size(base.Size) перед ретурном. Не суть...


А теперь ответь — как будет работать код, если ты ему передаёшь прямоугольник в указателе на квадрат? Скажем, для вычисления площади? Или, скажем, не площадь нужна, а равномерное распределение фигур по экрану?
Имхо нехилые грабли
Ну не соблюдается LSP ни разу!
Re[9]: Кто автор?
От: gbear Россия  
Дата: 22.07.05 10:18
Оценка: -1
Здравствуйте, Курилка, Вы писали:

G>>Реализация R.get_Size может быть различной.... такой какой нам нужно будет — вплоть до вызова R.set_Size(base.Size) перед ретурном. Не суть...


К>А теперь ответь — как будет работать код, если ты ему передаёшь прямоугольник в указателе на квадрат? Скажем, для вычисления площади? Или, скажем, не площадь нужна, а равномерное распределение фигур по экрану?

К>Имхо нехилые грабли
К>Ну не соблюдается LSP ни разу!

LSP требует лишь чтобы агрегат мог работать с потомками агригируемого класса. Сие означает, что наследуемое поведение должно соблюдаться потомками. И именно в варианте S<-R (и, что странно, этот вариант тут (The Liskov Substitution Principle) не рассмотрен ) это можно "вылечить" реализацией. Если агрегат работает (хочет работать) с R как с S, то R для этого агрегата станет S'ом. Он это сможет сделать. В варианте R<-S — S, как не "выкручивай" реализацию, LSP нарушит.

Суть не в этом... Я точно уверен, что рассматриваемая задача не имеет к LSP никакого отношения. Т.к. ставится и разрешается ещё на уровне этапа анализа предметной области — когда у нас ещё нет ни классов, ни, уж тем более, сигнатур методов и т.п.

---
С уважением, Сиваков Константин.
Re[5]: Кто автор?
От: mibe  
Дата: 22.07.05 10:42
Оценка:
Здравствуйте, cranky, Вы писали:

M>>А если рассмотреть целые и действительный числа — что из них родитель, а что предок?


C>Думается, что у них просто общий абстрактный предок (или интерфейс), определяющий общие операции.


Почитайте UML Nontation Guide:
*есть отношение обобщение — отношение частного и общего (is a)
*есть наследование — передача признаков от одного к другому
Так как любое целое является действительным, то действительное предок целого.
--
Far.Net
Re: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 22.07.05 14:10
Оценка:
Здравствуйте, gbear, Вы писали:

G>Вопрос: Кто из них родитель, а кто предок? Почему?[/i]


G>Я всегда считал, что в свое время "подсмотрел" её у Буча... Но вот что-то сегодня полистал его — ничего похожего не нашёл. Но, блин, вряд ли я её сам придумал


Обсуждалось уже
Автор: Gaperton
Дата: 03.11.03
Re[8]: Кто автор?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 23.07.05 07:29
Оценка:
Здравствуйте, gbear, Вы писали:

G>По сути одно... В контракте квадрата будет "лишняя" функциональность унаследованная от прямоугольника (работа со вторым размером).


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


Классический косяк, вызванный тем, что обычно наследование вызывает и наследование интерфейсов, и наследование реализаций. А в данном конкретном случае как не выбери — либо интерфейсы наследуются криво, либо реализации. ИМХО правильным решением этой задачи было бы наследование интерфейсов без наследования реализаций. Примерно так:
public interface IRectangle
{
    int Width
    {get;}
    
    int Height
    {get;}
}

public class Rectangle : IRectangle
{
    private int _width;
    private int _height;
    
    public int Width
    {
        get { return _width; }
    }
    
    public int Height
    {
        get { return _height; }
    }
}

public class Square : IRectangle
{
    private int _size;
    
    public int Size
    {
        get { return _size; }
    }
    
    int IRectangle.Width
    {
        get { return Size; }
    }
    
    int IRectangle.Height
    {
        get { return Size; }
    }
}

Итого: имеем оптимальные публичные интерфейсы в каждом случае и возможность обработки полиморфно.
... << RSDN@Home 1.2.0 alpha rev. 585>>
AVK Blog
Re[5]: Кто автор?
От: Mamut Швеция http://dmitriid.com
Дата: 23.07.05 11:03
Оценка: 1 (1)
ANS>>Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.

E>По-моему, фамилия Лисков не склоняется. По крайней мере везде в русскоязычной литературе было написано "принцип Лисков (Барбара Лисков)", а не "принцип Лисковой"


Иностранные женские фамилии не склоняются (вроде, есть некоторое количество исключений, но их слишком мало). Поэтому, если Лисков — это Барбара, то будет:

И. Барбара Лисков
Р. Барбары Лисков
Д. Барбаре Лисков
В. Барбару Лисков
Т. Барбарой Лисков
П. О Барбаре Лисков


dmitriid.comGitHubLinkedIn
Re[6]: Кто автор?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 23.07.05 11:16
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Иностранные женские фамилии не склоняются (вроде, есть некоторое количество исключений, но их слишком мало). Поэтому, если Лисков — это Барбара, то будет:


Лисков -- это таки Барбара
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Кто автор?
От: Павел Кузнецов  
Дата: 23.07.05 21:52
Оценка:
AndrewVK,

A>
 A> public interface IRectangle
 A> {
 A>  int Width
 A>  {get;}

 A>  int Height
 A>  {get;}
 A> }

 A> public class Rectangle : IRectangle <...>

 A> public class Square : IRectangle
 A> {
 A>  private int _size;

 A>  public int Size
 A>  {
 A>   get { return _size; }
 A>  }

 A>  int IRectangle.Width
 A>  {
 A>   get { return Size; }
 A>  }

 A>  int IRectangle.Height
 A>  {
 A>   get { return Size; }
 A>  }
 A> }
 A>

A> Итого: имеем оптимальные публичные интерфейсы в каждом случае и
A> возможность обработки полиморфно.

А теперь давай добавим в IRectangle модификацию...
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[10]: Кто автор?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 23.07.05 22:03
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>А теперь давай добавим в IRectangle модификацию...


И в чем проблема?
... << RSDN@Home 1.2.0 alpha rev. 585>>
AVK Blog
Re[11]: Кто автор?
От: Павел Кузнецов  
Дата: 23.07.05 22:58
Оценка:
AndrewVK,

ПК>> А теперь давай добавим в IRectangle модификацию...


A> И в чем проблема?


В том, что в случае модификации высоты квадрата через интерфейс
IRectangle будет также изменяться и ширина, и наоборот. Если же
квадрат не будет менять высоту синхронно с шириной, он перестанет
быть квадратом. Нарушение инвариантов класса.

Давай представим простой код:
void SetDimensions( IRectangle rectangle, int width, int height )
{
  rectangle.SetWidth( width );
  rectangle.SetHeight( height );

  assert( rectangle.Width() == width );
  assert( rectangle.Height() == height );
}

В случае передачи в эту функцию квадрата, ее постусловия будут
нарушены. Т.е. функция не будет корректно работать с квадратами.
Нарушение критерия Барбары Лисков.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Кто автор?
От: OnThink Россия http://vassilsanych.livejournal.com
Дата: 24.07.05 15:26
Оценка: +2
Здравствуйте, gbear, Вы писали:

G>Вопрос: Кто из них родитель, а кто предок? Почему?[/i]


никто не родитель:
круг не является квадратом
квадрат не является кругом
родителем должен быть абстракный объект — фигура

ИМХО именно так
иначе — глубокое непонимание сути наследования
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[12]: Кто автор?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 24.07.05 16:26
Оценка: +3
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В том, что в случае модификации высоты квадрата через интерфейс

ПК>IRectangle будет также изменяться и ширина, и наоборот. Если же
ПК>квадрат не будет менять высоту синхронно с шириной, он перестанет
ПК>быть квадратом. Нарушение инвариантов класса.

Нет, это недостаточная конкретизированность исходной задачи. Тут надо определиться — либо квадрат всего лишь одно из состояний прямоугольника, тогда создание отдельного класса для квадрата бессмысленно, достаточно отдельной функции IsSquare, либо квадрат это особый класс фигуры. Но тогда надо определиться с семантикой операции изменения одного из измерений квадрата. К примеру, если речь идет о некоем векторном редакторе, у которого есть панелька с шириной и высотой, то изменение другого измерения совместно с первым вполне нормальное и ожидаемое поведение. Если в том же редакторе мы хотим разнообразить поведение, для прямоугольника показать два измерения, а для квадрата одно, то задачка решается введением метаданых, привязанных к фигуре и отдельным интерфейсом на чтение и модификацию. В таком раскладе IRectangle по прежнему остается только для чтения, что позволяет работать полиморфным алгоритмам рассчета площади, к примеру, а вот модификация осуществляется другими интерфейсами, например ISingleDimensionShape и IDoubleDimensionShape.
Могут быть и другие решения. Все зависит от задачи.

ПК>Давай представим простой код:

ПК>
ПК>void SetDimensions( IRectangle rectangle, int width, int height )
ПК>{
ПК>  rectangle.SetWidth( width );
ПК>  rectangle.SetHeight( height );

ПК>  assert( rectangle.Width() == width );
ПК>  assert( rectangle.Height() == height );
ПК>}
ПК>

ПК>В случае передачи в эту функцию квадрата, ее постусловия будут
ПК>нарушены. Т.е. функция не будет корректно работать с квадратами.
ПК>Нарушение критерия Барбары Лисков.

Нет. Это значит что критерии, использованные для проектирования интерфейсов иные, нежели критерии для проектирования того куска кода, что ты привел. В нем assert написаны исходя из предположения, что Width это просто поле. Но, поскольку на самом деле это не поле, то, в общем случае, делать предположений о тривиальной логике модификаций измерений мы не имеем права, если это специально не оговорено в документации.
... << RSDN@Home 1.2.0 alpha rev. 592>>
AVK Blog
Re[13]: Кто автор?
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 25.07.05 05:31
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Нет, это недостаточная конкретизированность исходной задачи. Тут надо определиться — либо квадрат всего лишь одно из состояний прямоугольника, тогда создание отдельного класса для квадрата бессмысленно, достаточно отдельной функции IsSquare, либо квадрат это особый


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

Кстати, этой проблемы с нарушением инвариантов не будет если не будет мутирующих методов.
... << RSDN@Home 1.1.4 stable rev. 510>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[6]: Кто автор?
От: stalcer Россия  
Дата: 25.07.05 06:04
Оценка:
Здравствуйте, mibe, Вы писали:

M>Почитайте UML Nontation Guide:

M> *есть отношение обобщение — отношение частного и общего (is a)
M> *есть наследование — передача признаков от одного к другому

Че-то первый раз слышу. Где конкретно читать?
http://www.lmdinnovative.com (LMD Design Pack)
Re[14]: Кто автор?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 25.07.05 08:49
Оценка:
Здравствуйте, Andrei N.Sobchuck, Вы писали:

AVK>>Нет, это недостаточная конкретизированность исходной задачи. Тут надо определиться — либо квадрат всего лишь одно из состояний прямоугольника, тогда создание отдельного класса для квадрата бессмысленно, достаточно отдельной функции IsSquare, либо квадрат это особый


ANS>Как по мне, то это самое правильное решение.


Нельзя делать столь определенный вывод, не зная исходных условий.
... << RSDN@Home 1.2.0 alpha rev. 594>>
AVK Blog
Re[4]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 25.07.05 13:36
Оценка: 1 (1)
Здравствуйте, mihoshi, Вы писали:

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


LK>>>Считаю, что правильный ответ: родитель — квадрат.


C>>скорее прямоугольник, у него ширина и высота, а квадрат — это уже его специализация, где w==h


M>А если рассмотреть целые и действительный числа — что из них родитель, а что предок?


Мне больше нравится другой пример, в нем соблазнов больше.

Комплексные и действительные числа, у которых кроме арифметики определена модифицирующая операция (метод) взятия квадратного корня TakeSqrt().
Re[2]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 25.07.05 13:57
Оценка: 3 (2) +2
Здравствуйте, LtrK2, Вы писали:

LK>Я не в курсе, увы. И задачу вижу в первый раз.

LK>Считаю, что правильный ответ: родитель — квадрат.
LK>Можно узнать правильный ответ?

Вот определение наследования:
B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что
1) он является экземпляром А (B подмножество А)
2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).

Ваш пример нарушает пункт 1 определения наследования, так как любой прямоугольник — это не квадрат. Все ровно наоборот. Если делать наоборот — то нарушится пункт 2, так как, например, операция прямоугольника изменяющая его ширину, выводит квадрат из класса квадратов. А изменять семантику этой операции тоже нельзя — тогда нарушится принцип подстановки Лисков. Вот этот принцип:
Если B пронаследован от А, то любая программа, работающая с А, должна корректно работать и с экземплярами В.

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

Так что правильный ответ — они вообще не связаны наследованием. В этом суть всех подобных задач (круг — эллипс, дествительное — комплексное число, итд). Правильно их решить может только человек, знакомый с теорией.
Re[5]: Кто автор?
От: okurietz Россия  
Дата: 25.07.05 14:34
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Andrei N.Sobchuck, Вы писали:


ANS>>Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.


E>По-моему, фамилия Лисков не склоняется. По крайней мере везде в русскоязычной литературе было написано "принцип Лисков (Барбара Лисков)", а не "принцип Лисковой"

Фамилии то склоняются... но только мужские.
т.е. если бы это был мужчина, то принцип Лискова
(с) правила русского языка.

Хорошо видно по корейским фамилиям — Ким Наталье, Киму Антону.
Re[6]: Кто автор?
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 25.07.05 14:57
Оценка:
Здравствуйте, okurietz, Вы писали:

ANS>>>Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.


E>>По-моему, фамилия Лисков не склоняется. По крайней мере везде в русскоязычной литературе было написано "принцип Лисков (Барбара Лисков)", а не "принцип Лисковой"

O>Фамилии то склоняются... но только мужские.
O>т.е. если бы это был мужчина, то принцип Лискова
O>(с) правила русского языка.

O>Хорошо видно по корейским фамилиям — Ким Наталье, Киму Антону.


Н-да. Век живи, век учись, а результат зараннее определён
Буду знать.
... << RSDN@Home 1.1.4 stable rev. 510>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[14]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 25.07.05 17:38
Оценка: 57 (1) +1
Здравствуйте, Andrei N.Sobchuck, Вы писали:

ANS>Кстати, этой проблемы с нарушением инвариантов не будет если не будет мутирующих методов.


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

Короче, это безусловно некий подход, но он не только решает проблемы, но также их и создает — только другие.
Re[9]: Кто автор?
От: gbear Россия  
Дата: 26.07.05 04:13
Оценка: +2
Здравствуйте, AndrewVK, Вы писали:

AVK>Классический косяк, вызванный тем, что обычно наследование вызывает и наследование интерфейсов, и наследование реализаций.


Хм... Таки под наследованием (inheritance, generalization) понимается именно наследование реализации. Когда имеется ввиду наследование интерфейсов — говорят о реализации (implementation). ИМХО.

---
С уважением, Сиваков Константин.
Re[3]: Кто автор?
От: gbear Россия  
Дата: 26.07.05 05:04
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Вот определение наследования:

G>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что
G>1) он является экземпляром А (B подмножество А)
G>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).

Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.


G>Ваш пример нарушает пункт 1 определения наследования, так как любой прямоугольник — это не квадрат.


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

G>Все ровно наоборот.


Угу... Т.к. квадрат "прикинуться" прямоугольником не может.

G>Если делать наоборот — то нарушится пункт 2, так как, например, операция прямоугольника изменяющая его ширину, выводит квадрат из класса квадратов. А изменять семантику этой операции тоже нельзя — тогда нарушится принцип подстановки Лисков. Вот этот принцип:

G>Если B пронаследован от А, то любая программа, работающая с А, должна корректно работать и с экземплярами В.

G>Другими словами, если вместо А поставить экземпляр В то любая корректно написанная программа должна продолжить работать корректно, или наследование применено не по назначению. Этот же принцип нарушается и при вашем решении — программа, работающая с базовым классом "квадрат" предполагает, что стороны у этой фигуры равны.


Угу... и что, у прямоугольника стороны обязаны быть не равны?! Или A.get_Size не может быть переопределена в B.get_Size таким образом, что B.Width = B.Height? Другое дело, что вообще говоря, это несколько... коряво что ли. Но тем не менее. Программа будет корректно работать. Так что, ИМХО, вариант S<-R, в общем случае, ППЛ не нарушает... в отличие от варианта R<-S.

G>Не составит труда придумать такую программу, работающую с квадратом, штоб она вела себя некорректно при замене квадрата на прямоугольник.


Сильно сомневаюсь... Все зависит от контракта квадрата, и его реализации в прямоугольнике.

G>Так что правильный ответ — они вообще не связаны наследованием. В этом суть всех подобных задач (круг — эллипс, дествительное — комплексное число, итд). Правильно их решить может только человек, знакомый с теорией.


Вообще говоря, основной вопрос в задаче — почему

А мой, вопрос — кто автор?

Ещё раз повторюсь: Задача ставится в терминах OOA.

---
С уважением, Сиваков Константин
Re[4]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 26.07.05 12:02
Оценка:
Здравствуйте, gbear, Вы писали:

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


G>>Вот определение наследования:

G>>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что
G>>1) он является экземпляром А (B подмножество А)
G>>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).

G>Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.


Пункт 2 возникает из простого факта, что модифицирующая операция (метод) не может изменить тип (класс) объекта, т.е. является замкнутой. Так устроены все строготипизированные ОО языки, и абсолютное большинство динамически типизированых. К определению отношения "наследование" он имеет самое прямое отношение, так является частью этого определения в теории типа.

G>>Ваш пример нарушает пункт 1 определения наследования, так как любой прямоугольник — это не квадрат.


G> Только в том плане, что может задаваться двумя длинами, и может менять размеры сторон независимо друг от друга. Ключевое слово может. Т.е. прямоугольник, как это не абсурдно звучит, можно рассмотреть как специализацию "квадрата".


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

G>>Все ровно наоборот.

G>Угу... Т.к. квадрат "прикинуться" прямоугольником не может.
Все ровно наоборот. Квадрат всегда является прямоугольником. Пятый класс вторая четверть.

G>>Другими словами, если вместо А поставить экземпляр В то любая корректно написанная программа должна продолжить работать корректно, или наследование применено не по назначению. Этот же принцип нарушается и при вашем решении — программа, работающая с базовым классом "квадрат" предполагает, что стороны у этой фигуры равны.


G> Угу... и что, у прямоугольника стороны обязаны быть не равны?!

Нет.
G>Или A.get_Size не может быть переопределена в B.get_Size таким образом, что B.Width = B.Height? Другое дело, что вообще говоря, это несколько... коряво что ли. Но тем не менее. Программа будет корректно работать.
Не будет программа корректно работать. Если базовый класс — прямоугольник, то следующая программа сломается при замене его на квадрат:

figure.SetHeight( 5 );
figure.SetLehgth( 10 );
value = figure.GetHeight() / ( figure.GetLength() - figure.GetHeight() ); // деление на ноль в случае квадрата


G>Так что, ИМХО, вариант S<-R, в общем случае, ППЛ не нарушает... в отличие от варианта R<-S.

G>>Не составит труда придумать такую программу, работающую с квадратом, штоб она вела себя некорректно при замене квадрата на прямоугольник.
G>Сильно сомневаюсь... Все зависит от контракта квадрата, и его реализации в прямоугольнике.
Совершенно неважно. Даже если удастся в конкретном случае извернуться, то в результате получится хрупкий дизайн, который разрушит всю систему при добавлении операций к квадрату и прямоугольнику. Нарушение первого пункта слишком фундаментально, и в любом случае с рук не сойдет.

Теперь о примере. Если базовый класс — квадрат, то следующая программа перестанет работать, если ей подпихнуть figure в виде прямоугольника со сторонами 5 и 10:

Вариант 1: Вы пытаетесь извернуться, и ввести отдельный метод для взятия длины ребра квадрата. Вот незадача, для большинства прямоугольников (которые не квадраты) он вести себя корректно не может, и будет бросать exception. Вуаля.
size = figure.GetSquareSize();


Все остальные варианты: Допустим, он не бросает exception, а возвращает одну из сторон. Тогда вы нарушите инвариант базового класса, который состоит вот в чем: GetSquareSize() ^ 2 == GetArea(). Мне написать программу, которая будет себя вести некорректно, или вы это сможете сделать сами? То же самое касается и всех остальных вариантов — всегда будет возможность подсунуть такой прямоугольник, который нарушит инвариант базового класса.

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

G>>Так что правильный ответ — они вообще не связаны наследованием. В этом суть всех подобных задач (круг — эллипс, дествительное — комплексное число, итд). Правильно их решить может только человек, знакомый с теорией.

G>Вообще говоря, основной вопрос в задаче — почему
В силу природы вещей.

G>А мой, вопрос — кто автор?

Скорее всего — Барбара Лисков.

G>Ещё раз повторюсь: Задача ставится в терминах OOA.

Ну да, а я о чем по вашему говорю?
Re[5]: Кто автор?
От: gbear Россия  
Дата: 27.07.05 04:38
Оценка: -1
Здравствуйте, Gaperton, Вы писали:

G>>Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.


G>Пункт 2 возникает из простого факта, что модифицирующая операция (метод) не может изменить тип (класс) объекта, т.е. является замкнутой. Так устроены все строготипизированные ОО языки, и абсолютное большинство динамически типизированых. К определению отношения "наследование" он имеет самое прямое отношение, так является частью этого определения в теории типа.


Спасибо, я понял, что имеется ввиду.

G>>>Ваш пример нарушает пункт 1 определения наследования, так как любой прямоугольник — это не квадрат.


G>> Только в том плане, что может задаваться двумя длинами, и может менять размеры сторон независимо друг от друга. Ключевое слово может. Т.е. прямоугольник, как это не абсурдно звучит, можно рассмотреть как специализацию "квадрата".


G>Любой квадрат является прямоугольником. Некоторые прямоугольники являются квадратами. Следовательно, множество всевозможных квадратов является подмножеством множества прямоугольников. Ключевое слово — подмножество.


С точки зрения геометрии — безусловно. С точки зрения рассмотрения "поведений" этих сущностей — именно прямоугольники — подмножество квадратов. См. чуть ниже.

G>>>Все ровно наоборот.

G>>Угу... Т.к. квадрат "прикинуться" прямоугольником не может.
G>Все ровно наоборот. Квадрат всегда является прямоугольником. Пятый класс вторая четверть.

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

G>>>Другими словами, если вместо А поставить экземпляр В то любая корректно написанная программа должна продолжить работать корректно, или наследование применено не по назначению. Этот же принцип нарушается и при вашем решении — программа, работающая с базовым классом "квадрат" предполагает, что стороны у этой фигуры равны.


G>Не будет программа корректно работать. Если базовый класс — прямоугольник, то следующая программа сломается при замене его на квадрат:


Мы о чем?! Яж не спорю о варианте R<-S... Я говорю что при варианте S<-R, в общем случае ППЛ не нарушается.

G>>Так что, ИМХО, вариант S<-R, в общем случае, ППЛ не нарушает... в отличие от варианта R<-S.


G>>>Не составит труда придумать такую программу, работающую с квадратом, штоб она вела себя некорректно при замене квадрата на прямоугольник.

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

Хм... Вы утверждаете, что квадрат теоритически может обладать таким поведением, которое не реализуемо (принципиально) в прямоугольнике?

G>Теперь о примере. Если базовый класс — квадрат, то следующая программа перестанет работать, если ей подпихнуть figure в виде прямоугольника со сторонами 5 и 10:


G>Вариант 1: Вы пытаетесь извернуться, и ввести отдельный метод для взятия длины ребра квадрата. Вот незадача, для большинства прямоугольников (которые не квадраты) он вести себя корректно не может, и будет бросать exception. Вуаля.

G>
G>size = figure.GetSquareSize();
G>


Хм... Смотрим:

class S
{
 virtual int Size
 {
  get{return _size;}
  set{_size = value;}
 }
 
 virtual int Area
 {
  return (_size * _size);
 }
}

class R: S
{
 int Height
 {
  get{return base.Size;}
  set{base.Size = value;}
 }
 
 int Width
 {
  get{retunr _width;}
  set{_width = value;}
 }

 override int Size
 {
  //Может быть перекрыт как угодно... напримет так.
  get
  {
   _width = base.Size;
   return base.Size;
  }
  set
  {
   _width = base.Size = value;
  }
 } 

 override int Area
 {
  return base.Size * _width;
 }
}


Так что мне не совсем понятно, о чем идет речь... Например, о каком специальном методе "взятия длины ребра квадрата" мы говорим? Следуя принципу достаточности контракта, этот метод должне быть в контракте квадрата... а вот свойств "ширина"/"высота" в контракте квадрата, по уму, быть не должно.

G>Все остальные варианты: Допустим, он не бросает exception, а возвращает одну из сторон. Тогда вы нарушите инвариант базового класса, который состоит вот в чем: GetSquareSize() ^ 2 == GetArea().


См. выше... Идея состоит в том, что если агрегат работает с прямоугольником через интерфейс квадрата — прямоугольник, для такого агрегата станет "квадратом"... Он может им стать. Всё поведение квадрата реализуемо в прямоугольнике.

G>Мне написать программу, которая будет себя вести некорректно, или вы это сможете сделать сами? То же самое касается и всех остальных вариантов — всегда будет возможность подсунуть такой прямоугольник, который нарушит инвариант базового класса.


Ещё раз... Все это "лечится" реализацией.

G>Вы почитайте старую ветку, ссылку на которую я давал — там очень подробно все обсуждалось.


Читал... Про вариант S<-R мало убедительного.

G>>Вообще говоря, основной вопрос в задаче — почему

G>В силу природы вещей.



G>>А мой, вопрос — кто автор?

G>Скорее всего — Барбара Лисков.

Вряд ли... Именно потому, что все рассуждение ведутся на уровне конкретных реализаций. Т.е. как мимнимум на уровне OOD...

G>>Ещё раз повторюсь: Задача ставится в терминах OOA.

G>Ну да, а я о чем по вашему говорю?

Тоже, как минимум на уровне OOD... Я уже говорил о том, что, если так можно выразиться, практический смысл задачи — выявление интерфейсных сущностей на этапе OOA.

---
С уважением, Сиваков Константин.
Re: Кто автор?
От: Socrat Россия  
Дата: 27.07.05 09:46
Оценка:
Здравствуйте, gbear, Вы писали:

G>День добрый...


G>Сорри, за возможный оффтоп, но вряд ли кто-либо кроме участников этого форума знает ответ.


G>Вопрос такой... Никто не в курсе, кто автор задачки "про квадрат и прямоугольник" (что-то типа):


G>Дано две сущности: квадрат и прямоугольник. Они обладают следующим поведением:


G>1. Предоставляют информацию о своих размерах.

G>2. Могут изменять свои размеры.
G>3. Предоставляют информацию о своей площади.

G>Вопрос: Кто из них родитель, а кто предок? Почему?


Вообще, можно сделать и так, и так. Вся загвоздка в возвращаемых параметрах. Если сначала описали сущность квадрата, у которого функция размера возвращает только длину одной стороны, то переопределить ее для прямоугольника будет сложновато...
Re[2]: Кто автор?
От: Socrat Россия  
Дата: 27.07.05 09:48
Оценка: :)
Здравствуйте, OnThink, Вы писали:

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


G>>Вопрос: Кто из них родитель, а кто предок? Почему?[/i]


OT>никто не родитель:

OT>круг не является квадратом
OT>квадрат не является кругом
OT>родителем должен быть абстракный объект — фигура

Квадрат — частный случай прямоугольника (впрочем, как и ромба...).
Re[6]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 27.07.05 11:26
Оценка:
Здравствуйте, gbear, Вы писали:

G>Хм... Смотрим:


G>
G>class S
G>{
G> virtual int Size
G> {
G>  get{return _size;}
G>  set{_size = value;}
G> }
 
G> virtual int Area
G> {
G>  return (_size * _size);
G> }
G>}

G>class R: S
G>{
G> int Height
G> {
G>  get{return base.Size;}
G>  set{base.Size = value;}
G> }
 
G> int Width
G> {
G>  get{retunr _width;}
G>  set{_width = value;}
G> }

G> override int Size
G> {
G>  //Может быть перекрыт как угодно... напримет так.
G>  get
G>  {
G>   _width = base.Size;
G>   return base.Size;
G>  }
G>  set
G>  {
G>   _width = base.Size = value;
G>  }
G> } 

G> override int Area
G> {
G>  return base.Size * _width;
G> }
G>}
G>


G>Так что мне не совсем понятно, о чем идет речь... Например, о каком специальном методе "взятия длины ребра квадрата" мы говорим? Следуя принципу достаточности контракта, этот метод должне быть в контракте квадрата... а вот свойств "ширина"/"высота" в контракте квадрата, по уму, быть не должно.


Ваша реализация нарушает инвариант базового класса, нарушая таким образом принцип подстановки Лисков. Конкретнее, вот этот код
int a1 = figure.Area();
int tmp = figure.Size();
if( a1 != figure.Area() )
   crash_system();

сработает для квадрата, но завалит систему, если figure является прямоугольником с неравными сторонами.

Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз?
Re[4]: Кто автор?
От: Oleg A. Bachin Украина  
Дата: 27.07.05 13:25
Оценка: +1
Здравствуйте, gbear, Вы писали:

G>>Вот определение наследования:

G>>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что
G>>1) он является экземпляром А (B подмножество А)
G>>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).

G>Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.


по моему там (в пункте 2) было еще что-то об недопустимости "усиления ограничений" или как-то так звучит.
т.е. если класс А имеет виртуальную функцию, в которой есть ограничение на входной параметр С от 0 до 5, то клаcc Б унаследованный от А не может накладывать более жесткие ограничения.
для класса Б:
0 < C < 10 — верно
0 < C < 2 — неверно
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Best regards,
Oleg A. Bachin
Re[5]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 27.07.05 14:49
Оценка:
Здравствуйте, Oleg A. Bachin, Вы писали:

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


G>>>Вот определение наследования:

G>>>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что
G>>>1) он является экземпляром А (B подмножество А)
G>>>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).

G>>Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.


OAB>по моему там (в пункте 2) было еще что-то об недопустимости "усиления ограничений" или как-то так звучит.

OAB>т.е. если класс А имеет виртуальную функцию, в которой есть ограничение на входной параметр С от 0 до 5, то клаcc Б унаследованный от А не может накладывать более жесткие ограничения.
OAB>для класса Б:
OAB>0 < C < 10 — верно
OAB>0 < C < 2 — неверно

Да, на самом деле там было жестко. Так накладывались ограничения не предусловия и постусловия для каждого метода А, перекрываемого в Б. Предусловие не может быть более сильным, а постусловие не может быть более слабым. Что-то в таком духе.

Я обычно заменяю это правилом подстановки Лисков — так проще.
Re[6]: Кто автор?
От: Oleg A. Bachin Украина  
Дата: 27.07.05 14:59
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Я обычно заменяю это правилом подстановки Лисков — так проще.


аналогично
просто уже все это на уровне посприятия, но после прочтения оставалось ощущение какой-то недосказанности...
попытался вспомнить чего не хватает — потом сформулировал
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Best regards,
Oleg A. Bachin
Re[7]: Кто автор?
От: gbear Россия  
Дата: 28.07.05 04:49
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Ваша реализация нарушает инвариант базового класса, нарушая таким образом принцип подстановки Лисков. Конкретнее, вот этот код

G>
G>int a1 = figure.Area();
G>int tmp = figure.Size();
G>if( a1 != figure.Area() )
G>   crash_system();
G>

G>сработает для квадрата, но завалит систему, если figure является прямоугольником с неравными сторонами.

Лишь по той простой причине, что ф-ция расчета площади виртуальна. Что, вообще говоря, сааавсем не обязательно.


G>Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз?


А смысл, если Вы до сих пор при виде варианта S<-R "тыкаете" в п.1. С чего Вы взяли что "квадрат" подмножество "прямоугольников"?! Только лишь на том, основании что любой квадрат, с т.з. геометрии, прямоугольник?! Но ведь тип-то, определяется реализуемым поведением... разве не так? И именно из этих соображений строятся все иерархии наследования — реализуемое поведение специализируется и расширяется вниз по иерархии. Т.е. говоря о подмножествах типов — мы говорим о подмножествах реализуемых ими поведений. Согласны? Иначе я не совсем понимаю, что Вы понимаете под п.1.

Второй момент — бессмысленно, имхо, рассуждать вообще о любом агрегате... Но, для варианта S<-R можно утверждать, что для для любого агрегата A, агригирующего S, всегда найдется такая реализация S и R:S, при которой: контракты S и R:S достаточны; инвариант S не нарушается A; R не противоречит ППЛ. С этим тоже не согласны? Причем имеенно только для варианта S<-R... Для варианта R<-S такого утвеждать нельзя.

Другое дело, что можно найти и такой агрегат, для которого вариант S<-R будет лишён смысла... не в том, плане что для него не будут выполняться выше указанные условия. А в том, что он нам ничего, кроме "лишней" связности, не даст.

Причем, рассуждая так, мы с вами автоматически "переносимся" в OOD, решая, совсем другую задачу

На уровне OOA у нас ещё нет даже формально описанного поведения — т.е. выраженного в терминах состояния и передачи сообщений. Оно у нас пока ещё описано неформально... простым человеческим языком, так сказать. Но уже на этом этапе, можно с изрядной долей уверенности утверждать, что классы, реализующие сущности с подобным (не подобным, описаному в задаче, а подобным друг другу) поведением, будут находится на одином уровне в иерархии классов. Просто протому, что смысл отношения наследования заключается даже не столько в специализации поведения, сколько в его расширеннии. Что для нас означает, что на N+1-ом уровне нам, собственно, нечего расширять... у нас нет дополнительного поведения. Мы можем лищь специализировать поведение определенное на N-ом уровне иерархии. При этом, мы должны быть точно уверены в том, что порождаемая связность — оправданы в нашем дизайне. Что, в общем случае, не очевидно.

Возвращаясь к наши баранам, мы не можем утвержать наличие/отсутвие дополнительного поведения у какой-либо из рассматриваемых сущностей без рассмотрения конкретного агрегата (которого на этапе OOA тоже может и не быть выявлено в надлежащей формализации). Собственно, по этому и утверждается, что задача не имеет конкретного правильного решения. Есть лишь теоритически верное предпосылка к тому, что бы определить некую "интерфейсную" сущность.

---
С уважением, Сиваков Константин.
Re[8]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 28.07.05 11:08
Оценка: +1
Здравствуйте, gbear, Вы писали:

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


G>>Ваша реализация нарушает инвариант базового класса, нарушая таким образом принцип подстановки Лисков. Конкретнее, вот этот код

G>>
G>>int a1 = figure.Area();
G>>int tmp = figure.Size();
G>>if( a1 != figure.Area() )
G>>   crash_system();
G>>

G>>сработает для квадрата, но завалит систему, если figure является прямоугольником с неравными сторонами.

G> Лишь по той простой причине, что ф-ция расчета площади виртуальна. Что, вообще говоря, сааавсем не обязательно.


Ну-ну. Для любого вашего варианта, какой бы вы ни придумали, будет существовать такая программа, которая будет вести себя некорректно в случае прямоугольника. Если вы это до сих пор не понимаете, то видимо, не поймете уже никогда.

G>>Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз?

G> А смысл, если Вы до сих пор при виде варианта S<-R "тыкаете" в п.1.

Смысл? Для вас смысл очень простой — если вы так уверены в себе, то я предлагаю вам на мне заработать. Ставлю, скажем, 50 баксов. Вы даете очередную реализацию — я пишу программу, которая ведет себя по разному для прямоугольника и квадрата. У меня получается — вы переводите мне 50 долларов. Почтовым переводом. Не получается — это делаю я. Выбираем арбитра — я предлагаю Синклера. Ну что, deal?

G>С чего Вы взяли что "квадрат" подмножество "прямоугольников"?!


Вы, должно быть, шутите, мистер Фейнман? С того, что у вас в условии заданы алгоритмы рассчета площади и публичные порперти, которые однозначно задают именно "квадрат" и именно "прямоугольник". Не существует других фигур, площадь которых рассчитывается по заданной схеме. Отсюда следует, что мы имеем дело именно с означенными геометрическими фигурами, а не сферическими конями в вакууме.

С того, что при проектировании (вы так на ООА напираете, что даже странно) вы прекрасено знаете, что имеете дело именно с квадратом и именно с прямоугольником. В принципе, даже последнего достаточно.

G>Собственно, по этому и утверждается, что задача не имеет конкретного правильного решения. Есть лишь теоритически верное предпосылка к тому, что бы определить некую "интерфейсную" сущность.


Она имеет вполне конкретные неправильные решения. И одно из них — ваше.
Re[2]: Кто автор?
От: vdimas Россия  
Дата: 28.07.05 13:27
Оценка:
Здравствуйте, mibe, Вы писали:

M>А еще бывают языки типа cecil где класс можно декларативно определить (типа квадрат это прямоугольник у которого длина=ширина) и конкретный объект классифицируется динамически на основе такого определения.


Я бы и на обычном языке программирования не вводил бы отдельный класс для квадрата. Я бы для прямоугольника ввел операцию, типа FixAspectRatio(double ratio), и при изменении любой из сторон затем вычислял другую. Соответственно, для конкретной нужды в квадрате FixSpectRatio(1).
И далее:
bool IsQuadrant { return GetAspecRation()==1.0; }
Re[9]: Кто автор?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.07.05 14:03
Оценка: +1
Здравствуйте, Gaperton, Вы писали:

G>Если вы это до сих пор не понимаете, то видимо, не поймете уже никогда.


На грани фола.
... << RSDN@Home 1.2.0 alpha rev. 596>>
AVK Blog
Re[9]: Кто автор?
От: gbear Россия  
Дата: 29.07.05 03:36
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Ну-ну. Для любого вашего варианта, какой бы вы ни придумали, будет существовать такая программа, которая будет вести себя некорректно в случае прямоугольника. Если вы это до сих пор не понимаете, то видимо, не поймете уже никогда.


Так же, будет существовать и программа (агрегат), которая будет вести себя корректно. Причем (в который раз уже повторяюсь) это рассуждения из области OOD... И, как Вы сами, прекрасно знаете, если мы говорим не о библиотеке, сначала выявляются и описываются агрегаты, а потом уже все остальное. Или у Вас все наоборот? Если же мы имеем ввиду "программу", как библиотеку, то мы, как авторы этой библиотеки, вполне можем наложить ограничения а типы агрегатов использующих её. Разве нет?

G>>>Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз?

G>> А смысл, если Вы до сих пор при виде варианта S<-R "тыкаете" в п.1.

G>Смысл? Для вас смысл очень простой — если вы так уверены в себе, то я предлагаю вам на мне заработать. Ставлю, скажем, 50 баксов. Вы даете очередную реализацию — я пишу программу, которая ведет себя по разному для прямоугольника и квадрата. У меня получается — вы переводите мне 50 долларов. Почтовым переводом. Не получается — это делаю я. Выбираем арбитра — я предлагаю Синклера. Ну что, deal?


Ну не красиво же... право слово.

Второй момент — бессмысленно, имхо, рассуждать вообще о любом агрегате... Но, для варианта S<-R можно утверждать, что для для любого агрегата A, агригирующего S, всегда найдется такая реализация S и R:S, при которой: контракты S и R:S достаточны; инвариант S не нарушается A; R не противоречит ППЛ. С этим тоже не согласны? Причем имеенно только для варианта S<-R... Для варианта R<-S такого утвеждать нельзя.


Угу... Это я Вам сказал, в предыдущем посте. И что я слышу?! Мне вот просто интересно, что Вы ожидали услышать в ответ?

G>>С чего Вы взяли что "квадрат" подмножество "прямоугольников"?!


G>Вы, должно быть, шутите, мистер Фейнман? С того, что у вас в условии заданы алгоритмы рассчета площади и публичные порперти, которые однозначно задают именно "квадрат" и именно "прямоугольник". Не существует других фигур, площадь которых рассчитывается по заданной схеме. Отсюда следует, что мы имеем дело именно с означенными геометрическими фигурами, а не сферическими конями в вакууме.


Шучу? Шучу? Что, черт подери, я только что ляпнул? Вы разве не согласны с тем, что тип — суть поведение? Разве Вы не согласны с тем, что "вниз по иерархии" реализуемое типами поведение должно расширяться? Как минимум — специализироваться? Так объясните мне — почему, если все поведение квадрата, реализуемо прямоугольником, я не могу сказать, что прямоугольник "подтип" квадрата? Только лишь на том, основании, что с т.з. геометрии это не так?! Или может быть на том основании, что, вообще говоря, в определенный момент объект-прямоугольник может находится вне состояний объекта-квадрата. Вас это пугает? Так ведь мы с Вами, как Вы верно подметили, не о шаровых (так смешней) конях рассуждаем... Спускаетесь до OOD — извольте агрегат. Вам что, тяжело представить себе, как Вы говорите, программу, которой эти нюансы, образно выражаясь, сугубо фиалетовы?

G>С того, что при проектировании (вы так на ООА напираете, что даже странно) вы прекрасено знаете, что имеете дело именно с квадратом и именно с прямоугольником. В принципе, даже последнего достаточно.


И что с того?! Вас послушать, так получается что я принципиально не могу связывать наследованием такие сущности как квадрат (дался он мне) и круг. Просто на том основаннии, что. Так что ли?

G>>Собственно, по этому и утверждается, что задача не имеет конкретного правильного решения. Есть лишь теоритически верное предпосылка к тому, что бы определить некую "интерфейсную" сущность.


G>Она имеет вполне конкретные неправильные решения. И одно из них — ваше.


Конкретно, неправильное решение, это вариант R<-S. Для варианта S<-R существуют агрегаты, и такие реализации S и R:S, при которых... и т.д. Ну Вы поняли

---
С уважением, Сиваков Константин.
Re[10]: Кто автор?
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.07.05 04:42
Оценка: +2
Здравствуйте, gbear, Вы писали:

G>Шучу? Шучу? Что, черт подери, я только что ляпнул? Вы разве не согласны с тем, что тип — суть поведение? Разве Вы не согласны с тем, что "вниз по иерархии" реализуемое типами поведение должно расширяться? Как минимум — специализироваться? Так объясните мне — почему, если все поведение квадрата, реализуемо прямоугольником, я не могу сказать, что прямоугольник "подтип" квадрата?

Нет. Гапертон уже с десяток постов, как продемонстрировал, что и у прямоугольника и у квадрата есть поведения, которые невозможно корректно реализовать в другой фигуре.

G> И что с того?! Вас послушать, так получается что я принципиально не могу связывать наследованием такие сущности как квадрат (дался он мне) и круг. Просто на том основаннии, что. Так что ли?

Нет, технически, конечно, можно. Но с точки зрения OOA это бред, т.к. как только ты введешь в одну из сущностей специфичное для нее поведение, как наследник не сможет его корректно реализовать.

G>Конкретно, неправильное решение, это вариант R<-S. Для варианта S<-R существуют агрегаты, и такие реализации S и R:S, при которых... и т.д. Ну Вы поняли

Не существует таких реализаций. Максимум, на который можно рассчитывать — это наследование обоих от единого базового класса/интерфейса. При этом он будет настолько убогим, что не сможет иметь практической ценности.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Кто автор?
От: gbear Россия  
Дата: 29.07.05 13:04
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


Пример поведения реализуемого в квадрате, и теоритически нереализуемого в прямогугольнике в студию. После этого и продолжим разговор.

---
С уважением, Сиваков Константин.
Re[12]: Кто автор?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 29.07.05 13:16
Оценка: 1 (1) +2
Здравствуйте, gbear, Вы писали:

G>Пример поведения реализуемого в квадрате, и теоритически нереализуемого в прямогугольнике в студию. После этого и продолжим разговор.


Получение круга, который касается всех четырех сторон. Пойдет?
... << RSDN@Home 1.2.0 alpha rev. 596>>
AVK Blog
Re[10]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 29.07.05 15:37
Оценка:
Здравствуйте, gbear, Вы писали:

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


G>>Ну-ну. Для любого вашего варианта, какой бы вы ни придумали, будет существовать такая программа, которая будет вести себя некорректно в случае прямоугольника. Если вы это до сих пор не понимаете, то видимо, не поймете уже никогда.


G> Так же, будет существовать и программа (агрегат), которая будет вести себя корректно.

Принцип подстановки Лисков, которому должны удовлетворять подтипы, требует корректного поведения от любой программы при замене типа на подтип. Чувствуете разницу между "любой" и "будет существовать"?

G>>>>Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз?

G>>> А смысл, если Вы до сих пор при виде варианта S<-R "тыкаете" в п.1.

G>>Смысл? Для вас смысл очень простой — если вы так уверены в себе, то я предлагаю вам на мне заработать. Ставлю, скажем, 50 баксов. Вы даете очередную реализацию — я пишу программу, которая ведет себя по разному для прямоугольника и квадрата. У меня получается — вы переводите мне 50 долларов. Почтовым переводом. Не получается — это делаю я. Выбираем арбитра — я предлагаю Синклера. Ну что, deal?


G> Ну не красиво же... право слово.

Вы меня убиваете, право слово. Я вам тут считай даром 50 баксов предлагаю , само по себе нивираятна блаародный и красивый поступок, вот. Причем все честно — Синклер человек строгих правил и не допустит тут никакого жульничества. А вы, можно сказать, раздающему, то есть мне, прикуп в морду швыряете. За что?!

G>

G>Второй момент — бессмысленно, имхо, рассуждать вообще о любом агрегате... Но, для варианта S<-R можно утверждать, что для для любого агрегата A, агригирующего S, всегда найдется такая реализация S и R:S, при которой: контракты S и R:S достаточны; инвариант S не нарушается A; R не противоречит ППЛ. С этим тоже не согласны?


1) ППЛ сам по себе предполагает, что при фиксированных R и S все возможные программы А будут работать корректно, в том смысле, что с точки зрения А (еще раз — совершенно любого А для фиксированных S и R) нет никакой разницы между S и его подклассом R.
2) Вы пишете, что если для заданых S и R существует хотя бы один такой А, что он не может различить S от R, то выполняется ППЛ. Это, очевидно неправда — см пункт 1. Из того, что заданным свойстом обладает единственный элемент множества, никак не следует, что им обладают все элементы, а именно этого требует ППЛ. Вы можете задаться вопросом: почему? Это уже другая история, но можем поговорить и об этом.

G>Угу... Это я Вам сказал, в предыдущем посте. И что я слышу?! Мне вот просто интересно, что Вы ожидали услышать в ответ?


Я ожидал услышать в ответ: я согласен. Вот вам моя программа. И, чуть позже: куда переводить деньги? 50 баксов, сами понимаете, не лишние.

G>>>С чего Вы взяли что "квадрат" подмножество "прямоугольников"?!


G>>Вы, должно быть, шутите, мистер Фейнман? С того, что у вас в условии заданы алгоритмы рассчета площади и публичные порперти, которые однозначно задают именно "квадрат" и именно "прямоугольник". Не существует других фигур, площадь которых рассчитывается по заданной схеме. Отсюда следует, что мы имеем дело именно с означенными геометрическими фигурами, а не сферическими конями в вакууме.


G>Шучу? Шучу? Что, черт подери, я только что ляпнул? Вы разве не согласны с тем, что тип — суть поведение? Разве Вы не согласны с тем, что "вниз по иерархии" реализуемое типами поведение должно расширяться? Как минимум — специализироваться? Так объясните мне — почему, если все поведение квадрата, реализуемо прямоугольником, я не могу сказать, что прямоугольник "подтип" квадрата?


Слушайте, я вам привел определение подтипа из теории типа. Прямоугольник, определенный так как это сделано в задаче, не может являться подтипом квадрата. Он нарушает инварианты базового класса, или принцип подстановки Лисков, что по сути одно и то же. Поэтому я не могу сказать, что прямоугольник подтип квадрата. Но вам — можно.

G>Вас это пугает? Так ведь мы с Вами, как Вы верно подметили, не о шаровых (так смешней) конях рассуждаем... Спускаетесь до OOD — извольте агрегат. Вам что, тяжело представить себе, как Вы говорите, программу, которой эти нюансы, образно выражаясь, сугубо фиалетовы?


Нет, не тяжело, я видел в жизни много плохо спроектированых систем. Мне будет тяжело такую программу поддерживать и развивать. В определенный момент (который довольно скоро наступит) ее придется просто выбросить (так будет существенно дешевле) как ярко выраженый образчик хрупкого дизайна, трещащий по швам при любой модификации.

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

G>>С того, что при проектировании (вы так на ООА напираете, что даже странно) вы прекрасено знаете, что имеете дело именно с квадратом и именно с прямоугольником. В принципе, даже последнего достаточно.


G> И что с того?! Вас послушать, так получается что я принципиально не могу связывать наследованием такие сущности как квадрат (дался он мне) и круг. Просто на том основаннии, что. Так что ли?


Принципиально вы можете делать все что угодно, кто же вам запретит. Речь идет не о том, что вы можете, а о том, что вы считаете даже не допустимым — а хорошим, правильным. Сделаете плохо — сами потом пожалеете. Ну или ваши коллеги пожалеют, кому модифицировать систему придется .

G>>>Собственно, по этому и утверждается, что задача не имеет конкретного правильного решения. Есть лишь теоритически верное предпосылка к тому, что бы определить некую "интерфейсную" сущность.


G>>Она имеет вполне конкретные неправильные решения. И одно из них — ваше.


G>Конкретно, неправильное решение, это вариант R<-S. Для варианта S<-R существуют агрегаты, и такие реализации S и R:S, при которых... и т.д. Ну Вы поняли


Я-то понял.... Вы неправильно понимаете принцип Лисков. Вот и вся проблема. Он не может выполняться для некоторых А. Он обязан выполнятся для всех А, иначе это никакой не принцип Лисков.
Re[11]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 29.07.05 16:42
Оценка: 1 (1) +1
Здравствуйте, Sinclair, Вы писали:

S> Максимум, на который можно рассчитывать — это наследование обоих от единого базового класса/интерфейса. При этом он будет настолько убогим, что не сможет иметь практической ценности.


Ну, насчет убожества третьего базового класса- здесь, пожалуй, не соглашусь. Вот, например:

class Figure
{
public:
   // вот это было в примере
   virtual double GetArea() const = 0;

// а вот это вполне могло бы быть...
   virtual void Draw( Canvas & ) const = 0;
   virtual bool HasIntersection( const Figure & ) const = 0;
   vurtual bool Contains( const Point & ) const = 0;

// а вот это спорно, но вполне жизненно, и ППЛ не нарушает
protected:
   Point m_disp;
   double m_magnificationRatio;
   double m_angle;

   void ApplyAffineTransform( const Transform & ) {...}
};
Re[13]: Кто автор?
От: Cyberax Марс  
Дата: 30.07.05 11:18
Оценка:
AndrewVK wrote:

> G>Пример поведения реализуемого в квадрате, и *теоритически*

> нереализуемого в прямогугольнике в студию. После этого и продолжим
> разговор.
> Получение круга, который касается всех четырех сторон. Пойдет?

Вспомнилось: "Овал — это круг, вписанный в квадрат со сторонами 3 на 4".
А если серьезно, то при желании можно представить прямоугольник как
результат преобразования квадрата.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[12]: Кто автор?
От: Cyberax Марс  
Дата: 30.07.05 12:02
Оценка:
Gaperton wrote:

> S> Максимум, на который можно рассчитывать — это наследование обоих от

> единого базового класса/интерфейса. При этом он будет настолько
> убогим, что не сможет иметь практической ценности.
> Ну, насчет убожества третьего базового класса- здесь, пожалуй, не
> соглашусь. Вот, например:
>
>class Figure
>{
>public:
> // вот это было в примере
> virtual double GetArea() const = 0;
>
>// а вот это вполне могло бы быть...
> virtual void Draw( Canvas & ) const = 0;
> virtual bool HasIntersection( const Figure & ) const = 0;
> vurtual bool Contains( const Point & ) const = 0;
>
>// а вот это спорно, но вполне жизненно, и ППЛ не нарушает
>protected:
> Point m_disp;
> double m_magnificationRatio;
> double m_angle;
>
> void ApplyAffineTransform( const Transform & ) {...}
>};
>
Начнем критиковать c метода Draw:

Предположим, что фигура "квадрат" будет рисоваться на канвасе с помощью
четырех линий. А если завтра мы захотим добавить другой тип канваса
(например, рендерер в PostScript), в котором есть специальный
оптимизированый метод для рисования прямоугольника? С квадратом,
конечно, разницы не будет никакой, а вот с закрашеной областью,
ограниченой кривыми Безье — разница уже вполне может быть.

Поэтому метода Draw у абстрактной фигуры быть не должно, должны быть
отдельные объекты-рендереры.

Точно такие же возражения насчет интерсекторов — они тоже должны быть
выделены в отдельную иерархию. Например, для некоторых сцен может быть
построено BSP-дерево, значительно ускоряющее нахождение пересечений.

Метод Contains можно вынести в интерсекторы, но можно и оставить как
крайний случай.

Ну и m_magnification, m_angle и m_disp лучше представить в виде
однородного преобразования.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[14]: Кто автор?
От: cranky Украина  
Дата: 30.07.05 13:07
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>А если серьезно, то при желании можно представить прямоугольник как

C>результат преобразования квадрата.

... как и произвольный параллелепипед. Всего лишь надо матрицу 2х2 хранить в объекте. Интересно, это применимо где-нибудь на практике?
You aren't expected to absorb this
Re[13]: Кто автор?
От: gbear Россия  
Дата: 01.08.05 02:39
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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


G>>Пример поведения реализуемого в квадрате, и теоритически нереализуемого в прямогугольнике в студию. После этого и продолжим разговор.


AVK>Получение круга, который касается всех четырех сторон. Пойдет?


Неа...

Вариант 1. Ввести данную оп-цию в контракт квадрата. virtual Circle S.GetCircumcircle(). И перекрыть её в прямоугольнике.

Вариант 2. Строим агрегат Circle A.GetGetCircumcircle(Square s). В этом случае перекрываем R.get_Size. Например, таким образом, чтобы R.Width = base.Size.

---
C уважением, Сиваков Константин.
Re[13]: Кто автор?
От: Oleg A. Bachin Украина  
Дата: 01.08.05 06:28
Оценка:
Здравствуйте, AndrewVK, Вы писали:

G>>Пример поведения реализуемого в квадрате, и теоритически нереализуемого в прямогугольнике в студию. После этого и продолжим разговор.


AVK>Получение круга, который касается всех четырех сторон. Пойдет?


ответ пойдет, только вопрос не в тему. ведь если квадрат наследуется от прямоугольника, он вполне логично расширяет функционал!
например TStream->TFileStream. вы ведь не настаиваете на функционале "запись в файл" у базового класса?

логичный вопрос должен был звучать в обратную сторону — "какая ф-ция прямоугольника, для класса квадрат изменяет поведение базового класса прямоугольник".
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Best regards,
Oleg A. Bachin
Re[14]: Кто автор?
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.08.05 08:14
Оценка: +3
Здравствуйте, Oleg A. Bachin, Вы писали:
OAB>ответ пойдет, только вопрос не в тему. ведь если квадрат наследуется от прямоугольника, он вполне логично расширяет функционал!
Нет. Квадрат, будучи отнаследованным от прямоугольника, исказит его контракт.
Например, удвоение ширины учетверит площадь вместо удвоения.
OAB>например TStream->TFileStream. вы ведь не настаиваете на функционале "запись в файл" у базового класса?
Нет. TStream не дает никаких обещаний, которые нарушит TFileStream. А вот TMemoryStream ты никак от TFileStream не отнаследуешь, как, впрочем, и наоборот.
OAB>логичный вопрос должен был звучать в обратную сторону — "какая ф-ция прямоугольника, для класса квадрат изменяет поведение базового класса прямоугольник".
Логичный вопрос, в общем-то, такой: "Почему новички отказываются читать литературу"? Все по поводу кругов/эллипсов и квадратов/прямоугольников было обсосано до мельчайших косточек. Ничего нового в этой области изобрести не удастся.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Кто автор?
От: Oleg A. Bachin Украина  
Дата: 01.08.05 08:27
Оценка: 1 (1) +1 :)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Oleg A. Bachin, Вы писали:

OAB>>ответ пойдет, только вопрос не в тему. ведь если квадрат наследуется от прямоугольника, он вполне логично расширяет функционал!
S>Нет. Квадрат, будучи отнаследованным от прямоугольника, исказит его контракт.
S>Например, удвоение ширины учетверит площадь вместо удвоения.
OAB>>например TStream->TFileStream. вы ведь не настаиваете на функционале "запись в файл" у базового класса?
S>Нет. TStream не дает никаких обещаний, которые нарушит TFileStream. А вот TMemoryStream ты никак от TFileStream не отнаследуешь, как, впрочем, и наоборот.
OAB>>логичный вопрос должен был звучать в обратную сторону — "какая ф-ция прямоугольника, для класса квадрат изменяет поведение базового класса прямоугольник".
S>Логичный вопрос, в общем-то, такой: "Почему новички отказываются читать литературу"? Все по поводу кругов/эллипсов и квадратов/прямоугольников было обсосано до мельчайших косточек. Ничего нового в этой области изобрести не удастся.

э... я вообщет и не спорю — я все прекрасно понимаю... только одно не понятно.
не желающий прочитать литературу и понять базовые принципы ООП, еще может унаследовать квадрат от прямоугольника, но обратное наследование я вообще не представляю кто может сделать! я лишь на этом акцентировал внимание
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Best regards,
Oleg A. Bachin
Re: Кто автор?
От: mefrill Россия  
Дата: 01.08.05 08:39
Оценка:
Здравствуйте, gbear, Вы писали:

G>Вопрос: Кто из них родитель, а кто предок? Почему?[/i]


Родитель прямоугольник. Потому, что каждый квадрат является прямоугольником, но не каждый прямоугольник является квадратом.
Re[11]: Кто автор?
От: gbear Россия  
Дата: 01.08.05 11:07
Оценка: :)
Здравствуйте, Gaperton, Вы писали:

G>> Так же, будет существовать и программа (агрегат), которая будет вести себя корректно.


G>Принцип подстановки Лисков, которому должны удовлетворять подтипы, требует корректного поведения от любой программы при замене типа на подтип. Чувствуете разницу между "любой" и "будет существовать"?


Хм... я так понимаю Вы об этом:

If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T — BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 (May, 1988). .


Если да, то прежде чем... желательно бы услышать от Вас же расшифровку понятий: all programs, и behavior is unchanged И лучше бы перед тем как... почитать таки оригинал. Это поможет снять некоторые вопросы. И может быть Вам после этого станет ясно, почему, например, уже в определении ПЛВ нет этих терминов.

Далее... может быть... очень может быть, что мы изначально друг друга не понимаем... мой косяк. Попытаюсь исправиться... В рассуждениях о варианте S<-R я виду речь о т.н. behavioural subtyping... очень надеюсь на то, что Вам знаком этот термин.

G>> Ну не красиво же... право слово.

G>Вы меня убиваете, право слово. Я вам тут считай даром 50 баксов предлагаю , само по себе нивираятна блаародный и красивый поступок, вот. Причем все честно — Синклер человек строгих правил и не допустит тут никакого жульничества. А вы, можно сказать, раздающему, то есть мне, прикуп в морду швыряете. За что?!

За навязчивость Яж Вам открытым текстом сказал буквально: "Знаю-знаю... давайте об этом не будем".

<Следующие два пункта пока поскипаны. Ввиду того, что мы с Вами, пока (надеюсь) разговариваем о разных вещах.>

G>Я ожидал услышать в ответ: я согласен. Вот вам моя программа. И, чуть позже: куда переводить деньги? 50 баксов, сами понимаете, не лишние.




G>>>>С чего Вы взяли что "квадрат" подмножество "прямоугольников"?!


G>Слушайте, я вам привел определение подтипа из теории типа.


Вот с этого места можно по подробней... Что за теория. Работы по... авторов. Буду весьма презнателем. На сей момент, как это не прескорбно, единственная известная мне "теория типов" не имеет никакого отношения к OOA, и уж тем более к OOD.

G>Прямоугольник, определенный так как это сделано в задаче, не может являться подтипом квадрата. Он нарушает инварианты базового класса, или принцип подстановки Лисков, что по сути одно и то же. Поэтому я не могу сказать, что прямоугольник подтип квадрата. Но вам — можно.


1. Где Вы в условиях задачи усмотрели "определение" прямоугольника?! Тем более "такое как"?
2. Ещё раз извиняюсь за то, что сразу не указал Вам на то, что все рассуждения о варианте S<-R ведутся мной в терминах BS.


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


Хм... М'сье считает "хрупкость" безусловным злом?!

Ну да вопрос-то не в этом... Хрупкий дизайн, может и не противоречить чему-либо. Главное, что бы шаг в сторону повышения хрупкости был осознаным.

---
С уважением, Сиваков Константин.
Re[14]: Кто автор?
От: Павел Кузнецов  
Дата: 01.08.05 11:55
Оценка:
Oleg A. Bachin,

AVK>> Получение круга, который касается всех четырех сторон. Пойдет?


OAB> ответ пойдет, только вопрос не в тему. ведь если квадрат наследуется

OAB> от прямоугольника, он вполне логично расширяет функционал! например
OAB> TStream->TFileStream. вы ведь не настаиваете на функционале "запись в
OAB> файл" у базового класса?

Это ровно обратный пример. В данном случае предлагали унаследовать
прямоугольник от квадрата:

Вы разве не согласны с тем, что тип — суть поведение? Разве Вы не согласны
с тем, что "вниз по иерархии" реализуемое типами поведение должно расширяться?
Как минимум — специализироваться? Так объясните мне — почему, если все поведение
квадрата, реализуемо прямоугольником, я не могу сказать, что прямоугольник
"подтип" квадрата?

Т.е., если адаптировать твою аналогию, получится class TStream : TFileStream.

OAB> логичный вопрос должен был звучать в обратную сторону — "какая ф-ция

OAB> прямоугольника, для класса квадрат изменяет поведение базового класса
OAB> прямоугольник".

Для квадрата, унаследованного от прямоугольника, примеры "неправильных"
функций, ломающих программы, использующие прямоугольники, в случае их
замены на квадраты (прямое нарушение LSP), уже приводились: SetWidth,
SetHeight и т.п.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[12]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 01.08.05 12:35
Оценка: +1
Здравствуйте, gbear, Вы писали:

G>Хм... я так понимаю Вы об этом:


G>

G>If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T — BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 (May, 1988). .


G>Если да, то прежде чем... желательно бы услышать от Вас же расшифровку понятий: all programs, и behavior is unchanged


Специально для вас — переведу на русский весь абзац. Кстати, когда даете ссылку, неплохо давать ссылку на источник. Это так, к слову.

Если для любого o1 <- S найдется такой o2 <- T, что для любой программы p <- P, определенной в терминах T поведение p не изменится при замене o1 на o2, то S является подтипом T.


G>И лучше бы перед тем как... почитать таки оригинал. Это поможет снять некоторые вопросы. И может быть Вам после этого станет ясно, почему, например, уже в определении ПЛВ нет этих терминов.

О, у меня появился вопрос, который надо снять. А что такое "определение ПЛВ"? Вы разъясните пожелуйста, или дайте ссылку на оригинал, а то вдруг это какой-нибудь очередной килограмм на ампер с сайта udaff.com, и мне следует обидиться?

G>Далее... может быть... очень может быть, что мы изначально друг друга не понимаем... мой косяк. Попытаюсь исправиться...

Отчего же, я понимаю вас очень хорошо.

G>В рассуждениях о варианте S<-R я виду речь о т.н. behavioural subtyping... очень надеюсь на то, что Вам знаком этот термин.

Я с самого начала давал именно поведенческое определение подтипа, очень странно, что вы этого не заметили. Ну да ладно, давайте сюда ваше определение "behavioral subtyping". И давайте посмотрим, каким образом оно сделает вашу ошибку правильным решением.

G>Ну да вопрос-то не в этом... Хрупкий дизайн, может и не противоречить чему-либо. Главное, что бы шаг в сторону повышения хрупкости был осознаным.

Мы таких на работу не берем с самого начала. Поэтому не приходится и увольнять — очень удобно.
Re[7]: Кто автор?
От: mibe  
Дата: 01.08.05 12:45
Оценка:
Здравствуйте, stalcer, Вы писали:

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


M>>Почитайте UML Nontation Guide:

M>> *есть отношение обобщение — отношение частного и общего (is a)
M>> *есть наследование — передача признаков от одного к другому

S>Че-то первый раз слышу. Где конкретно читать?


Я прогнал. Вот что нашёл.
...
5.28 GENERALIZATION
5.28.1 Semantics
Generalization is the taxonomic relationship between a more general element and a more specific
element that is fully consistent with the first element and that adds additional information. It is used
for classes, packages, use cases, and other elements.
--
Far.Net
Re[2]: Кто автор?
От: Павел Кузнецов  
Дата: 01.08.05 12:54
Оценка: 2 (2) +2
mefrill,

G>> Вопрос: Кто из них родитель, а кто предок? Почему?[/i]


m> Родитель прямоугольник. Потому, что каждый квадрат является

m> прямоугольником, но не каждый прямоугольник является квадратом.

Это верно для математики, т.к. она "рассуждает" в терминах свойств, и в общем
случае неверно для программирования, т.к. оно "рассуждает" в терминах поведения.

Например, в программировании изменение свойства "ширина" данного прямоугольника --
вполне нормальная ситуация. В математике же соответствующей операцией является
создание нового прямоугольника, с новыми свойствами. Соответственно, нужно очень
осторожно переносить отношения между понятиями, принятые в математике, на
отношения между понятиями, вводимыми в программировании.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Кто автор?
От: mibe  
Дата: 01.08.05 13:14
Оценка:
Здравствуйте, vdimas, Вы писали:

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


M>>А еще бывают языки типа cecil где класс можно декларативно определить (типа квадрат это прямоугольник у которого длина=ширина) и конкретный объект классифицируется динамически на основе такого определения.


V>Я бы и на обычном языке программирования не вводил бы отдельный класс для квадрата.


а я бы сделал
class Rectangle // прямоугольник
class MutableRectangle extends Rectangle // прямоугольник, который можно изменять (добавляются сеттеры)
class Square extends Rectangle // квадрат
class MutableSquare extends Square // квадрат, который можно изменять
--
Far.Net
Re: Кто автор?
От: stalcer Россия  
Дата: 01.08.05 13:39
Оценка: 1 (1)
Выскажу свое мнение по этому вопросу.

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

Т.е. мы изначально имеем два противоположных условия. Ну, тогда о какой полиморфной работе с изменением длин сторон вообще может идти речь ?

Чтение длин — да, можно сделать полиморфно, при помощи общего интерфейса. Кстати, довольно-таки распротраненный случай, когда чтение состояния объектов различных типов может быть сделано через один интерфейс, а вот изменения делаются разными способами.

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

class Rectangle
{
    public int Width  
    {
        get { return _width; }
    }
    public int Height
    {
        get { return _height; }
    }
    public virtual void SetBounds(int width, int height)
    {
        _width  = width;
        _height = height;
    }
    
    private int _width;
    private int _height;
}

class Square: Rectangle
{
    public override void SetBounds(int width, int height)
    {
        if (width != height)
            throw Exception("...");
            
        base.SetBounds(width, height);
    }
}


Но, здесь нарушается другой принцип. Так называемый Open-Closed принцип. Так как мы класс Rectangle спроектировали специально из расчета наличия класса Square.

Итак повторю, что мы изначально имеем два противоположных условия. И мне непонятно в какой-такой правильно спроектированной с точки зрения ООП программе может потребоваться полиморфное изменение длин сторон при наличии таких условий.
http://www.lmdinnovative.com (LMD Design Pack)
Re[3]: Кто автор?
От: mefrill Россия  
Дата: 01.08.05 14:29
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:


ПК>Это верно для математики, т.к. она "рассуждает" в терминах свойств, и в общем

ПК>случае неверно для программирования, т.к. оно "рассуждает" в терминах поведения.

Не уверен. Мне кажется, что понятие объекта выведено из понятия машины Тьюринга. Алгоритм в ООП представляет собой совокупность трех фаз: инициализацию объектов, обмен сообщениями и завершение. Результат работы программы есть совокупность состояний объектов-участников. С этой точки зрения, объекты представля.т собой просто объединения состояний машины Тьюринга. Каждое состояние задается соответствующим свойством, а значение состояния — значением свойства. В противном случае, непонятно как можно доказать корректность или некорректность того или иного алгоритма или вообще, возможность алгоритмизации данной задачи в терминах ООП. С этой точки зрения, что же представляют собой объекты-совокупности состояний? В программной модели они отражают онтологию мира, для которого идет моделирование. Что же такое онтология? Это, прежде всего, иерархия отношений. Из них, отношение "быть чем-то" является основным. На теоретико-множественном языке оно формируется как "принадлежность". Принцип Лисков как раз и закрепляет эту самую иерархию как принцип моделированния. В любом случае, необходимо четко определить что такое "оно "рассуждает" в терминах поведения", иначе будет большая путаница.

ПК>Например, в программировании изменение свойства "ширина" данного прямоугольника --

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

Согласен, все зависит от точки зрения. Но, мое глубокое убеждение состоит в том, что ООП как раз и введено специально для того, чтобы привнести рассуждения "математического типа", т.е. типа статического, описательного, в мир динамический, детерминированный и поведенческий. Отсюда и дуализм восприятия понятия "объект". Но, первичным при моделированнии, мне кажется, все же должен быть описательный подход. Т.е. сначала вводим понятия, определяем их свойства и отношения между ними, а потом начинаем интерпретировать эти понятия поведенчески, как машины состояний. Иначе нет совершенно никакого смысла в ООП, все можно запрограммировать простой тьюринговской машиной, т.е. совокупностью процедур.

Относительно приведенного примера не совсем согласен. Под прямоугольником в математике (по крайней мере, в элементарной геометрии) понимается как конкретный прямоугольник, так и некий абстрактный прямоугольник, представляющий собой совокупность некоторого множества прямоугольников. Например, когда я пишу "возмем прямоугольник ABCD, имеющий ширину 2 см и длину 5 см", то имею ввиду кокретный прямоугольник. А когда я пишу "пусть ABCD — некоторый прямоугольник, у которого ширина в два раза больше высоты", то я имею ввиду уже совокупность некоторых прямоугольников. В программировании это четко разделено понятиями объекта и его экземпляра, а в обыденном языке, частью которого является язык математический — нет. Экземпляр объекта прямоугольника не является сам прямоугольником, он лишь указывает, т.е. выделяет некоторый прямоугольник во множестве всех прямоугольников, и изменение ширины экземпляра объекта приводит только к тому, что в результате выделяется новый прямоугольник с требуемыми свойствами. Совсем непонятно также, что такое "создание нового прямоугольника, с новыми свойствами". Элементарная геометрия не создает и не уничтожает прямоугольники и вообще, любые сущности. Иначе, пришлось бы иметь дело с понятием времени, что в корне повлияло бы на сущность логики, применяющейся в математических рассуждениях.
Re[13]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 01.08.05 14:38
Оценка: +1
Здравствуйте, Cyberax, Вы писали:

C>Начнем критиковать c метода Draw:

Все бы вам критиковать.

C>Предположим, что фигура "квадрат" будет рисоваться на канвасе с помощью

C>четырех линий. А если завтра мы захотим добавить другой тип канваса
C>(например, рендерер в PostScript), в котором есть специальный
C>оптимизированый метод для рисования прямоугольника?

Кто вам сказал, какой интерфейс предполагается в канвасе? У меня что-то на эту тему сказано? Может быть, у меня в базовом классе Canvas всегда определен метод для рисования прямоугольника через линии, а в подклассах (например, для postscript) он перекрывается с целью оптимизиции?

C> С квадратом,

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

C>Поэтому метода Draw у абстрактной фигуры быть не должно, должны быть

C>отдельные объекты-рендереры.
Все сильно зависит от того, что именно мы пишем. Говорить вообще что должно или не должно быть можно только опираясь на всякие LSP, все остальное сильно зависит от задачи. Например, что если абстактная фигура состоит из нескольких элементарных фигур? Где отрисовку будем писать? В нашем случае есть где.

C>Точно такие же возражения насчет интерсекторов — они тоже должны быть

C>выделены в отдельную иерархию. Например, для некоторых сцен может быть
C>построено BSP-дерево, значительно ускоряющее нахождение пересечений.
Опять же, не понимаю, какие у вас могут быть возражения к дизайну в условиях отсутствия задачи. И еще мне не вполне понятно, как именно мне помешает умение фигур находить свои пересечения использовать в оптимизированном случае BSP деревья.

C>Метод Contains можно вынести в интерсекторы, но можно и оставить как

C>крайний случай.

C>Ну и m_magnification, m_angle и m_disp лучше представить в виде

C>однородного преобразования.
А вот это безусловно так.
Re[2]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 01.08.05 14:49
Оценка:
Здравствуйте, stalcer, Вы писали:

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

[skipped]

S>Но, здесь нарушается другой принцип. Так называемый Open-Closed принцип. Так как мы класс Rectangle спроектировали специально из расчета наличия класса Square.


Во-первых, здесь нарушается все тот же LSP, так как подпихивание квадрата в программу, корректно работающую с прямоугольниками, может легко ее сломать. Так что так делать не стоит. Во-вторых, единственный корректный способ извратиться существует — это сделать метод SetBounds константным, возвращающим новый экземпляр с измененными границами. Надщо немного изменить ваш пример — вот так (C++):

virtual Rectangle SetBounds(int width, int height) const;


Такое решение ничего не нарушает, кроме того, что лишает ваш объект состояния. Что тоже вполне может аукнуться в будущем, как только вам понядобятся фигуры, имеющие друг на друга циклические ссылки. Но в данном примере все будет хорошо.
Re[3]: Кто автор?
От: Cyberax Марс  
Дата: 01.08.05 16:16
Оценка:
Павел Кузнецов wrote:

> Например, в программировании изменение свойства "ширина" данного

> прямоугольника --
> вполне нормальная ситуация. В математике же соответствующей операцией
> является
> создание нового прямоугольника, с новыми свойствами. Соответственно,
> нужно очень
> осторожно переносить отношения между понятиями, принятые в математике, на
> отношения между понятиями, вводимыми в программировании.

Либо использовать языки, где изменение свойства достигается созданием
нового объекта, например: Clean, OCaml, Haskell. Часто математические
понятия очень хорошо ложатся на функциональные языки.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[14]: Кто автор?
От: Cyberax Марс  
Дата: 01.08.05 16:34
Оценка:
Gaperton wrote:

> C>Предположим, что фигура "квадрат" будет рисоваться на канвасе с помощью

> C>четырех линий. А если завтра мы захотим добавить другой тип канваса
> C>(например, рендерер в PostScript), в котором есть специальный
> C>оптимизированый метод для рисования прямоугольника?
> Кто вам сказал, какой интерфейс предполагается в канвасе? У меня
> что-то на эту тему сказано? Может быть, у меня в базовом классе Canvas
> *всегда *определен метод для рисования прямоугольника через линии, а в
> подклассах (например, для postscript) он перекрывается с целью
> оптимизиции?

Тогда зачем нужен метод Draw у квадрата, если он просто будет
делегировать вызов канвасу? Зачем увеличивать связность объектной модели?

> C>С квадратом, конечно, разницы не будет никакой, а вот с закрашеной

> областью,
> C>ограниченой кривыми Безье — разница уже вполне может быть.
> C>Поэтому метода Draw у абстрактной фигуры быть не должно, должны быть
> C>отдельные объекты-рендереры.
> Все сильно зависит от того, что именно мы пишем. Говорить вообще что
> должно или не должно быть можно только опираясь на всякие LSP, все
> остальное сильно зависит от задачи. Например, что если абстактная
> фигура состоит из нескольких элементарных фигур? Где отрисовку будем
> писать? В нашем случае есть где.

Точно так же — в рендерерах. Делаем CompositeRenderer и вперед с песней.
Говорю из своего опыта автора графического редактора, кстати.

> C>Точно такие же возражения насчет интерсекторов — они тоже должны быть

> C>выделены в отдельную иерархию. Например, для некоторых сцен может быть
> C>построено BSP-дерево, значительно ускоряющее нахождение пересечений.
> Опять же, не понимаю, какие у вас могут быть возражения к дизайну в
> условиях отсутствия задачи. И еще мне не вполне понятно, как именно
> мне помешает умение фигур находить свои пересечения использовать в
> оптимизированном случае BSP деревья.

Не помешает, просто ненужно усложнит реализацию фигур.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[15]: Кто автор?
От: Cyberax Марс  
Дата: 01.08.05 16:37
Оценка:
cranky wrote:

> C>А если серьезно, то при желании можно представить прямоугольник как

> C>результат преобразования квадрата.
> ... как и произвольный параллелепипед. Всего лишь надо матрицу 2х2
> хранить в объекте. Интересно, это применимо где-нибудь на практике?

Такое вполне применимо, по-моему в Inkscape так и сделано.

Кстати, для двумерного случая хранят обычно не матрицу 2х2, а 3х3 — так
называемую матрицу однородного преобразования. В отличие от матрицы 2х2,
она позволяет задавать еще и параллельный перенос.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[15]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 01.08.05 16:55
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Gaperton wrote:


>> C>Предположим, что фигура "квадрат" будет рисоваться на канвасе с помощью

>> C>четырех линий. А если завтра мы захотим добавить другой тип канваса
>> C>(например, рендерер в PostScript), в котором есть специальный
>> C>оптимизированый метод для рисования прямоугольника?
>> Кто вам сказал, какой интерфейс предполагается в канвасе? У меня
>> что-то на эту тему сказано? Может быть, у меня в базовом классе Canvas
>> *всегда *определен метод для рисования прямоугольника через линии, а в
>> подклассах (например, для postscript) он перекрывается с целью
>> оптимизиции?

C>Тогда зачем нужен метод Draw у квадрата, если он просто будет

C>делегировать вызов канвасу? Зачем увеличивать связность объектной модели?

Во-первых — затем, что рисовать надо именно фигуры, а не что-нибудь еще. Во-вторых, фигура совсем не обязана быть настолько простой, чтобы маппится 1-в-1 в вызов метода канваса. В-третьих, фигура знает, где она расположена, и вообще, много чего знает. В-четвертых, ваше предложение не по делу сложнее, чем этот вариант, при сомнительных плюсах.

>> C>С квадратом, конечно, разницы не будет никакой, а вот с закрашеной

>> областью,
>> C>ограниченой кривыми Безье — разница уже вполне может быть.
>> C>Поэтому метода Draw у абстрактной фигуры быть не должно, должны быть
>> C>отдельные объекты-рендереры.
>> Все сильно зависит от того, что именно мы пишем. Говорить вообще что
>> должно или не должно быть можно только опираясь на всякие LSP, все
>> остальное сильно зависит от задачи. Например, что если абстактная
>> фигура состоит из нескольких элементарных фигур? Где отрисовку будем
>> писать? В нашем случае есть где.

C>Точно так же — в рендерерах. Делаем CompositeRenderer и вперед с песней.

C>Говорю из своего опыта автора графического редактора, кстати.

По вашим словам заметно, что вы так делали — вы говорите как надо, а не почему. Тем не менее, я не понимаю, как вы собираетесь переключать "рендереры" для фигур разных типов (виртуальный метод Draw для этого не подойдет? А что подойдет?). И совершенно не понимаю, зачем выделать рендерер в отдельный класс. Может, конечно, понадобиться. Но при каких условиях — не понятно.

>> C>Точно такие же возражения насчет интерсекторов — они тоже должны быть

>> C>выделены в отдельную иерархию. Например, для некоторых сцен может быть
>> C>построено BSP-дерево, значительно ускоряющее нахождение пересечений.
>> Опять же, не понимаю, какие у вас могут быть возражения к дизайну в
>> условиях отсутствия задачи. И еще мне не вполне понятно, как именно
>> мне помешает умение фигур находить свои пересечения использовать в
>> оптимизированном случае BSP деревья.

C>Не помешает, просто ненужно усложнит реализацию фигур.

С чего бы это?
Re[4]: Кто автор?
От: Павел Кузнецов  
Дата: 01.08.05 17:52
Оценка: 60 (3) +2
mefrill,

> ПК> Это верно для математики, т.к. она "рассуждает" в терминах свойств, и в общем случае неверно для программирования, т.к. оно "рассуждает" в терминах поведения.


> Не уверен. Мне кажется, что понятие объекта выведено из понятия машины Тьюринга. <...>


Я не говорил, что программирование не оперирует состоянием объектов. Моделирование в терминах поведения не отрицает наличия состояний. Совершенно согласен с твоей трактовкой поведения как сменяющих друг друга состояний. Просто, в программировании, по сравнению с математикой (той ее "статичной" частью, откуда пришло понятие квадрата как разновидности прямоугольника), акцент смещается с состояний как таковых на "законы" переходов между ними. Т.е. более важными становятся "инкременты" между состояниями, т.е. события, действия, — одним словом, поведение, т.к. именно оно приводит к "наблюдаемым явлениям": печать данных в консольном приложении, запись в файл, отрисовка картинки, запись в порт, управляющий манипулятором и т.п.

> Алгоритм в ООП представляет собой совокупность трех фаз: инициализацию объектов, обмен сообщениями и завершение. Результат работы программы есть совокупность состояний объектов-участников.


Ну, это если свести программирование к вычислительным задачам, главным результатом которых является набор некоторых конечных данных. И то, и то с точки зрения использования программы более существенным является ее воздействие на состояние окружения, а не ее внутреннее состояние (см. выше). Если же посмотреть на области, связанные с разнообразными процессами, то конечное состояние программы (равно как и внешнего окружения) как совокупности состояний объектов уступит приоритет последовательности состояний программы, и появятся понятия времени, допустимых переходов из данного состояния и т.п. Примеры: работа GUI, воспроизведение видео, системы управления и т.п.

> отношение "быть чем-то" является основным. На теоретико-множественном языке оно формируется как "принадлежность". Принцип Лисков как раз и закрепляет эту самую иерархию как принцип моделированния. В любом случае, необходимо четко определить что такое "оно "рассуждает" в терминах поведения", иначе будет большая путаница.


Говоря о «"рассуждении" в терминах поведения» я имел в виду, что в программировании, при проектировании классов, более существенными характеристиками объектов являются не его текущее состояние (object state), а набор допустимых состояний объекта (class invariants) и набор допустимых переходов из данного состояния в другие состояния (behavior), равно как принципиальной является и последовательность переходов между состояниями объекта. Противопоставляя это математике я имел в виду, что математика (по крайней мере, в части определения прямоугольников/квадратов) сосредотачивается на статических отношениях, как бы акцентируясь на состояниях-"снимках" объекта, если смотреть с точки зрения программирования.

Описание допустимых трансформаций всех возможных состояний объекта и есть его "поведение", задаваемое классом/типом данного объекта. Немаловажным с точки зрения упомянутого отличия от математики является и понятие identity объекта: для программирования, помимо прочего, существенным является то, какой именно объект перешел в какое именно состояние, а не просто рассмотрение отношений между состояниями, выражаемыми свойствами.

Барбара Лисков в соответствующей статье как раз и говорит о поведении, выделяя его как необходимое условие для существования отношения "is a subtype" между типами:

A type hierarchy is composed of subtypes and supertypes. The intuitive idea of a subtype is one whose objects provide all the behavior of objects of another type (the supertype) plus something extra. What is wanted here is something like the following substitution property [6]: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.


> мое глубокое убеждение состоит в том, что ООП как раз и введено специально для того, чтобы привнести рассуждения "математического типа", т.е. типа статического, описательного, в мир динамический, детерминированный и поведенческий. Отсюда и дуализм восприятия понятия "объект".


Объектно-ориентированное программирование родилось в результате попыток уменьшения сложности (information hiding), локализации изменений состояния (encapsulation). Как говорят, произошло это в процессе программирования систем симуляции, и именно в результате попыток выделить характерные черты в поведении сходных объектов. Т.е. ООП берет корни скорее в инженерных истоках программирования, чем в математических. К математике ближе "чистое" функциональное программирование, без мутирующих операций и т.п.

> первичным при моделированнии, мне кажется, все же должен быть описательный подход. Т.е. сначала вводим понятия, определяем их свойства и отношения между ними, а потом начинаем интерпретировать эти понятия поведенчески, как машины состояний.


На практике получается не вполне так. Обычно, для того, чтобы выделить свойства объетов, нужно, все-таки, сначала проанализировать их поведение (как говорят, собрать use cases).

> Иначе нет совершенно никакого смысла в ООП, все можно запрограммировать простой тьюринговской машиной, т.е. совокупностью процедур.


"В теории, нет разницы между теорией и практикой. На практике она есть."

Запрограммировать "простой тьюринговской машиной" можно все, только если мы об этом "всем" все знаем, и если это "все" в процессе, пока мы пытаемся его замоделировать, не изменяется. На практике мы узнаем об этом "всем" по мере, пока мы его моделируем, много нового, и в этом случае локализация поведения отдельных фрагментов состояния оказывается очень практичной.

> Относительно приведенного примера не совсем согласен. Под прямоугольником в математике (по крайней мере, в элементарной геометрии) понимается как конкретный прямоугольник, так и некий абстрактный прямоугольник, представляющий собой совокупность некоторого множества прямоугольников. Например, когда я пишу "возмем прямоугольник ABCD, имеющий ширину 2 см и длину 5 см", то имею ввиду кокретный прямоугольник. А когда я пишу "пусть ABCD — некоторый прямоугольник, у которого ширина в два раза больше высоты", то я имею ввиду уже совокупность некоторых прямоугольников. В программировании это четко разделено понятиями объекта и его экземпляра


Скорее, понятиями классов/типов и их экземпляров (объектов).

> Экземпляр объекта прямоугольника не является сам прямоугольником, он лишь указывает, т.е. выделяет некоторый прямоугольник во множестве всех прямоугольников, и изменение ширины экземпляра объекта приводит только к тому, что в результате выделяется новый прямоугольник с требуемыми свойствами.


Вот это и есть то, что я назвал "создание нового прямоугольника, с новыми свойствами". Для математики объектом изучения (по крайней мере, в случае прямоугольников/квадратов) является некоторый "снимок" жизни объекта программистского, его конкретное состояние. Т.е., конечно, математика включает изучение переходов между состояниями (трансформации и т.п.), но, как ты верно указал выше, когда дело доходит до конкретных прямоугольников и квадратов, с точки зрения математики проще называть прямоугольником/квадратом некоторое конкретное состояние, и считать, что трансформация приводит к созданию (если угодно, выделению) нового прямоугольника/квадрата, или, на другом языке, описывает соответствие между заданными прямоугольниками/квадратами.

С точки же зрения программирования часто удобнее называть прямоугольником/квадратом не отдельное состояние, а всю совокупность его состояний (object lifetime), сменяющихся в некоторой заданной области его хранения (region of storage), идентифицируемой данным объектом (object identity).

> Совсем непонятно также, что такое "создание нового прямоугольника, с новыми свойствами". Элементарная геометрия не создает и не уничтожает прямоугольники и вообще, любые сущности. Иначе, пришлось бы иметь дело с понятием времени, что в корне повлияло бы на сущность логики, применяющейся в математических рассуждениях.


Именно об этом я и говорил, упоминая необходимость критического использования выводов математики (в частности, и элементарной геометрии) в программировании.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[13]: Кто автор?
От: gbear Россия  
Дата: 02.08.05 04:22
Оценка:
Здравствуйте, Gaperton, Вы писали:

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


G>Специально для вас — переведу на русский весь абзац. Кстати, когда даете ссылку, неплохо давать ссылку на источник. Это так, к слову.


G>

G>Если для любого o1 <- S найдется такой o2 <- T, что для любой программы p <- P, определенной в терминах T поведение p не изменится при замене o1 на o2, то S является подтипом T.


Ой спасибо А я-то, тупил...

Тем не менее, таки, попрошу дать определение хотя бы "поведение p не изменится". Если у нас программа рисовала квадраты... и, вдруг, начала рисовать прямоугольники — изминилось или нет её поведение? Почему?

Насчет ссылок — а чем Вас библиографическая не устраивает?! Тем более, я сильно сомневаюсь, что это где-то ещё можно найти в открытом доступе.

G>>И лучше бы перед тем как... почитать таки оригинал. Это поможет снять некоторые вопросы. И может быть Вам после этого станет ясно, почему, например, уже в определении ПЛВ нет этих терминов.

G>О, у меня появился вопрос, который надо снять. А что такое "определение ПЛВ"? Вы разъясните пожелуйста, или дайте ссылку на оригинал, а то вдруг это какой-нибудь очередной килограмм на ампер с сайта udaff.com, и мне следует обидиться?

Вы меня удивляете ей богу... "Принцип Подстановки Лисков" Вам значит известен, а вот "Подтипы Лисков-Винг" (Liskov Wing Subtyping) значит нет?! Весело блин...

Subtype Requirement: Let phi(x) be a property provable about objects x of type T. Then phi(y) should be true for objects y of type S where S is a subtype of T.


Например, в "A Behavioral Notion of Subtyping" by Barbara Liskov and Jeannette Wing. ACM Transactions on Programming Languages and Systems, vol. 16, no. 6, Nov. 1994, pp. 1811-1841.

или в более поздней работе: Barbara Liskov, Jeanette Wing: "Behavioural Subtyping Using Invariants and Constraints", July 1999, CMU-CS-99-156 MIT Lab

G>>В рассуждениях о варианте S<-R я виду речь о т.н. behavioural subtyping... очень надеюсь на то, что Вам знаком этот термин.


G>Я с самого начала давал именно поведенческое определение подтипа, очень странно, что вы этого не заметили. Ну да ладно, давайте сюда ваше определение "behavioral subtyping". И давайте посмотрим, каким образом оно сделает вашу ошибку правильным решением.


Для начала указали бы мне на "ошибку"... а то я, по глупости своей, её так и не увидел. И уж тем более, я не увидел определения подтипа. Исключая, ту формуллировку ППЛ, что я привел в предыдущем посте. Если же Вы считаете ППЛ "поведенчиским" определением — то... ну я прям не знаю... Сама Лисков, в абстакт к "Behavioural Subtyping Using Invariants and Constraints" пишет что до сих пор им так и не удалось дать определения subtyping "based not only on type names and/or signatures, but also on a a description of the type's behaviour", и что в этой работе они сдвинулись с мертвой точки. Смешно...

---
С уважением, Сиваков Константин.
Re[3]: Кто автор?
От: stalcer Россия  
Дата: 02.08.05 05:53
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Во-первых, здесь нарушается все тот же LSP, так как подпихивание квадрата в программу, корректно работающую с прямоугольниками, может легко ее сломать.


Возникли две противоположные мысли:
— Конечно, если формально посмотреть, то LSP здесь нарушается (в соответствии с определением).
— С другой стороны, ужесточение предусловий — естественно для специализации. Хотя — спорный вопрос.

Например, TFileStream, открытый только на чтение, будет выбрасывать exception при попытке записи. Хотя, у базового TStream режимов (readOnly/readWrite) — нет. Повторюсь, вопрос спорный.

G>Так что так делать не стоит. Во-вторых, единственный корректный способ извратиться существует — это сделать метод SetBounds константным, возвращающим новый экземпляр с измененными границами. Надщо немного изменить ваш пример — вот так (C++):


G>
G>virtual Rectangle SetBounds(int width, int height) const;
G>


Вообще-то, нет абсолютно никакой разницы (с точки зрения LSP) между моим решением и твоим. Если, конечно, реализация Square::SetBounds осталась та же, т.е. с использованием throw.
http://www.lmdinnovative.com (LMD Design Pack)
Re[14]: Кто автор?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 02.08.05 10:12
Оценка:
Здравствуйте, gbear, Вы писали:

G>Неа...


G>Вариант 1. Ввести данную оп-цию в контракт квадрата. virtual Circle S.GetCircumcircle(). И перекрыть её в прямоугольнике.


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

G>Вариант 2. Строим агрегат Circle A.GetGetCircumcircle(Square s). В этом случае перекрываем R.get_Size. Например, таким образом, чтобы R.Width = base.Size.


В результате получаем семантически непонятный результат. Еще хуже.
... << RSDN@Home 1.2.0 alpha rev. 599>>
AVK Blog
Re[15]: Кто автор?
От: gbear Россия  
Дата: 02.08.05 11:05
Оценка:
Здравствуйте, AndrewVK, Вы писали:

Сорри... Я с описаной окружностью перепутал %)

Тем не менее, для реализации вписаной окружности достаточно реализовать в прямоугольнике привидение его к "квадратному" виду. Т.е. если мы обращаетмся к R.GetInscribedCircle() то R.Width становится равно S.Size.

A>В результате получаем семантически непонятный результат. Еще хуже.


Можно по подробней... о том, что Вы понимаете под "семантически непонятный"?

---
С уважением, Сиваков Константин.
Re[16]: Кто автор?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 02.08.05 11:39
Оценка:
Здравствуйте, gbear, Вы писали:

G>Тем не менее, для реализации вписаной окружности достаточно реализовать в прямоугольнике привидение его к "квадратному" виду. Т.е. если мы обращаетмся к R.GetInscribedCircle() то R.Width становится равно S.Size.


Т.е. делаем функционал, который в постановке задачи отсутствовал. Это называется архитектурной ошибкой.

A>>В результате получаем семантически непонятный результат. Еще хуже.


G>Можно по подробней... о том, что Вы понимаете под "семантически непонятный"?


В том, что смысл того функционала, о котором я говорил, применительно к пямоугольнику неясен.
... << RSDN@Home 1.2.0 alpha rev. 599>>
AVK Blog
Re[14]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 02.08.05 12:38
Оценка:
Здравствуйте, gbear, Вы писали:

G>>

G>>Если для любого o1 <- S найдется такой o2 <- T, что для любой программы p <- P, определенной в терминах T поведение p не изменится при замене o1 на o2, то S является подтипом T.


G>Ой спасибо А я-то, тупил...

Всегда пожалуйста.

G>Тем не менее, таки, попрошу дать определение хотя бы "поведение p не изменится". Если у нас программа рисовала квадраты... и, вдруг, начала рисовать прямоугольники — изминилось или нет её поведение? Почему?


Программа определена в терминах Т. Ее поведение не должно измениться именно в этих терминах. Это действительно немного путанный момент — можно мне переформулировать так, чтобы было понятнее?

Если для любого o1 <- S найдется такой o2 <- T, что не будет существовать такой программы p, которая при замене o1 на o2 способна определить эту замену, то S является подтипом T.


Насчет "определить замену" — на случай, если вы опять не поймете, поясню. Это означает, что вы не сможете написать программу, которая, пользуясь интерфейсом Т, могла бы понять, что ей подпихнули подтип этого Т — S.

Или, что то же самое, подтип не должен нарушать инвариантов типа.

В контексте этого разговора довольно забавно выглядят ваши слова.

И лучше бы перед тем как... почитать таки оригинал. Это поможет снять некоторые вопросы. И может быть Вам после этого станет ясно, почему, например, уже в определении ПЛВ нет этих терминов.


G>Насчет ссылок — а чем Вас библиографическая не устраивает?! Тем более, я сильно сомневаюсь, что это где-то ещё можно найти в открытом доступе.


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

G>Вы меня удивляете ей богу... "Принцип Подстановки Лисков" Вам значит известен, а вот "Подтипы Лисков-Винг" (Liskov Wing Subtyping) значит нет?! Весело блин...

Я не обязан уметь расшифровывать ваши КГАМ, извините. Ваши авторские аббревеатуры в институтах пока не преподают, да если бы и преподавали — уверяю вас, для меня нет ничего стыдного или удивительного в том, чтобы сказать, что я что-то не знаю — это слишком легко и просто исправить.

Так что извольте не удивляться, что вас не понимают, а изъясняться нормальным человеческим языком. Если, конечно хотите, чтобы вас понимали.

G>> Ну да ладно, давайте сюда ваше определение "behavioral subtyping". И давайте посмотрим, каким образом оно сделает вашу ошибку правильным решением.


G> Для начала указали бы мне на "ошибку"... а то я, по глупости своей, её так и не увидел.

Уже указывали двадцать раз. Бесполезно, вы каждый раз уводите разговор в сторону. Вы думаете, что выглядите умнее, отказывавясь признавать свою ошибку? Вы не правы, все ровно наоборот.

G>И уж тем более, я не увидел определения подтипа. Исключая, ту формуллировку ППЛ, что я привел в предыдущем посте.

http://www.rsdn.ru/Forum/Message.aspx?mid=1290517&amp;only=1
Автор: Gaperton
Дата: 25.07.05
Люди, знакомые с определением, его там увидели, несмотря на то, что я назвал это "наследованием". Ниже по ветке вы можете видеть дискуссию с Олегом на эту тему. Это, кстати, совершенно неважно, разговор не об этом.

Впрочем, я разговор заканчиваю, надоело смертельно. Всего доброго.
Re[4]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 02.08.05 12:46
Оценка:
Здравствуйте, stalcer, Вы писали:

S>Например, TFileStream, открытый только на чтение, будет выбрасывать exception при попытке записи. Хотя, у базового TStream режимов (readOnly/readWrite) — нет. Повторюсь, вопрос спорный.


Кто говорит, что LSP никто ни при каких обстоятельствах не нарушает?

S>Вообще-то, нет абсолютно никакой разницы (с точки зрения LSP) между моим решением и твоим. Если, конечно, реализация Square::SetBounds осталась та же, т.е. с использованием throw.


Есть огромная разница. И она состоит в том, что реализация Square::SetBounds, естественно, другая, и возвращает прямоугольник или квадрат — что получится. Т.е. работает абсолютно корректно, только выглядит крайне глупо . По сути, это получился фабричный метод, которому в принципе не нужен доступ к состоянию объекта. Поэтому, строго говоря, этот метод вообще не является операцией над прямоугольником, он статический .

Но это не сложно поправить — замените его на пару методов SetWidth и SetHeight, пусть они возвращают объект правильного класса для каждого сочетания размеров.
Re[5]: Кто автор?
От: stalcer Россия  
Дата: 02.08.05 13:09
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Кто говорит, что LSP никто ни при каких обстоятельствах не нарушает?


Да. Уж.

Что мы имеем:

1) ООП придумано, чтобы писать программы в терминах предметной области.
2) Принцип подстановки Лисков — один из принципов ООП.
3) С точки зрения нашей предметной области (математики) любой квадрат является прямоугольником.
4) Вся эта ветка форума показывает, что квадрат от прямоугольника наследовать нельзя, так как нарушается ППЛ.

Налицо явное противоречие. Значит один из пунктов неверный.
Подозреваю, нас злостно обманывали в школе и это пункт 3.

На самом деле, в математиеских изысканиях, мы оперируем понятиями точно также, как объектами в программе. Например, в ходе логического доказательства теоремы мы также "читаем" свойства понятий и также изменяем их. И я думаю, что вряд ли найдется математическое рассуждение, которое бы относилось полиморфно к прямоугольникам и квадратам в плане изменения длин их сторон. Так что, в математике квадрат является прямоугольником тоже только на "чтение" .
http://www.lmdinnovative.com (LMD Design Pack)
Re[5]: Кто автор?
От: stalcer Россия  
Дата: 02.08.05 13:24
Оценка:
Здравствуйте, Gaperton, Вы писали:

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


S>>Например, TFileStream, открытый только на чтение, будет выбрасывать exception при попытке записи. Хотя, у базового TStream режимов (readOnly/readWrite) — нет. Повторюсь, вопрос спорный.


G>Кто говорит, что LSP никто ни при каких обстоятельствах не нарушает?


Имхо, вот так LSP не нарушется:

class Stream
{
    public abstract bool IsReadonly();
    public abstract void Read(...);
    public abstract void Write(...);
}

class FileReadStream
{
    public override bool IsReadonly() { return true; }
    public override void Read(...)    { ... }
    public override void Write(...)   { throw ...; }
}


Убери функцию IsReadOnly из класса Stream, и LSP уже нарушается. Такой же трюк можно и с квадратом проделать. И опять же на практике применяемая фишка.
http://www.lmdinnovative.com (LMD Design Pack)
Re[4]: Кто автор?
От: Павел Кузнецов  
Дата: 02.08.05 13:28
Оценка:
stalcer,

G>> Во-первых, здесь нарушается все тот же LSP, так как подпихивание

G>> квадрата в программу, корректно работающую с прямоугольниками, может
G>> легко ее сломать.

s> Возникли две противоположные мысли:

s> — Конечно, если формально посмотреть, то LSP здесь нарушается (в
s> соответствии с определением).

И по сути тоже: если добавление подобного наследника может нарушить
соответствие существующего модуля своей спецификации, то, очевидно, что
таким действием мы делаем The Bad Thing.

s> — С другой стороны, ужесточение предусловий — естественно для

s> специализации.

Это просто означает, что "специализация" в таком понимании не связана с
отношением is-a.

s> Например, TFileStream, открытый только на чтение, будет выбрасывать

s> exception при попытке записи. Хотя, у базового TStream режимов
s> (readOnly/readWrite) — нет.

Если спецификация соответствующих методов TFileStream изначально говорила
о возможности соответствующих исключений, то подобное наследование LSP не
нарушает.

G>>
 G>> virtual Rectangle SetBounds(int width, int height) const;
 G>>


s> Вообще-то, нет абсолютно никакой разницы (с точки зрения LSP) между моим

s> решением и твоим. Если, конечно, реализация Square::SetBounds осталась
s> та же, т.е. с использованием throw.

Ну, здесь, вроде бы, очевидно, что в таком виде функция даже виртуальной не
должна быть, не говоря уже об исключениях.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Кто автор?
От: dshe  
Дата: 02.08.05 13:51
Оценка:
Здравствуйте, stalcer, Вы писали:

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


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


S>>>Например, TFileStream, открытый только на чтение, будет выбрасывать exception при попытке записи. Хотя, у базового TStream режимов (readOnly/readWrite) — нет. Повторюсь, вопрос спорный.


G>>Кто говорит, что LSP никто ни при каких обстоятельствах не нарушает?


S>Имхо, вот так LSP не нарушется:


S>Убери функцию IsReadOnly из класса Stream, и LSP уже нарушается. Такой же трюк можно и с квадратом проделать. И опять же на практике применяемая фишка.


Ага, а еще можно так (обобщая):
class Base {
    public abstract int GetType();
    public abstract void DoSomethingSpecialForDerived1();
    public abstract void DoSomethingSpecialForDerived2();
    public abstract void DoSomethingSpecialForDerivedN();
}
class Derived1: Base {
    public override int GetType() { return 1; }
    public override void DoSomethingSpecialForDerived1() { ... }
    public override void DoSomethingSpecialForDerived2() { throw ... }
    public override void DoSomethingSpecialForDerivedN() { throw ... }
}
class Derived2: Base {
    public override int GetType() { return 2; }
    public override void DoSomethingSpecialForDerived1() { throw ... }
    public override void DoSomethingSpecialForDerived2() { ... }
    public override void DoSomethingSpecialForDerivedN() { throw ... }
}
class DerivedN: Base {
    public override int GetType() { return N; }
    public override void DoSomethingSpecialForDerived1() { throw ... }
    public override void DoSomethingSpecialForDerived2() { throw ... }
    public override void DoSomethingSpecialForDerivedN() { ... }
}
--
Дмитро
Re[15]: Кто автор?
От: Павел Кузнецов  
Дата: 02.08.05 13:53
Оценка:
Gaperton,

G>> Тем не менее, таки, попрошу дать определение хотя бы "поведение p не

G>> изменится". Если у нас программа рисовала квадраты... и, вдруг, начала
G>> рисовать прямоугольники — изминилось или нет её поведение? Почему?

G> Программа определена в терминах Т. Ее поведение не должно измениться

G> именно в этих терминах. Это действительно немного путанный момент -
G> можно мне переформулировать так, чтобы было понятнее?

G> Если для любого o1 <- S найдется такой o2 <- T, что не будет
G> существовать такой программы p, которая при замене o1 на o2 способна
G> определить эту замену, то S является подтипом T.


Полагаю, более практично говорить соответствии программы своей спецификации,
при условии, что программа корректна, т.е. учитывает все возможные исходы
использования T, заданные его спецификацией. Говоря о поведении, Барбара
Лисков как раз говорит о спецификации и соответствии требованиям.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Кто автор?
От: Павел Кузнецов  
Дата: 02.08.05 13:53
Оценка:
stalcer,

s> 1) ООП придумано, чтобы писать программы в терминах предметной области.

s> 2) Принцип подстановки Лисков — один из принципов ООП.
s> 3) С точки зрения нашей предметной области (математики) любой квадрат является прямоугольником.
s> 4) Вся эта ветка форума показывает, что квадрат от прямоугольника наследовать нельзя, так как нарушается ППЛ.

s> Подозреваю, нас злостно обманывали в школе и это пункт 3.


В этом рассуждении три слабых места:

1) (Обычно) программа пишется не для математических доказательств,
соответственно, математика предметной областью не является.

2) Математические понятия квадрата и прямоугольника не предполагают от них
никакого поведения, соответственно, эти понятия в программе, наделяющей
соответствующие объекты поведением, могут использоваться очень ограниченно.

3) И да, понятия в программировании далеко не обязательно один-в один
соответствуют понятиям предметной области.

s> На самом деле, в математиеских изысканиях, мы оперируем понятиями точно

s> также, как объектами в программе. Например, в ходе логического
s> доказательства теоремы мы также "читаем" свойства понятий и также
s> изменяем их.

Относительно изменения есть серьезные сомнения...

s> И я думаю, что вряд ли найдется математическое рассуждение, которое бы

s> относилось полиморфно к прямоугольникам и квадратам в плане изменения
s> длин их сторон. Так что, в математике квадрат является прямоугольником
s> тоже только на "чтение" .

+1
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: Кто автор?
От: stalcer Россия  
Дата: 02.08.05 14:14
Оценка:
Здравствуйте, dshe, Вы писали:

D>Ага, а еще можно так (обобщая):

D>
D>class Base {
D>    public abstract int GetType();
D>    public abstract void DoSomethingSpecialForDerived1();
D>    public abstract void DoSomethingSpecialForDerived2();
D>    public abstract void DoSomethingSpecialForDerivedN();
D>}
D>


Ну, я же не писал IsFileReadStream(), а написал IsReadOnly(). В таком замаскированном виде смотрится куда приятней .
http://www.lmdinnovative.com (LMD Design Pack)
Re[7]: Кто автор?
От: stalcer Россия  
Дата: 02.08.05 14:14
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В этом рассуждении три слабых места:


ПК>1) (Обычно) программа пишется не для математических доказательств,

ПК>соответственно, математика предметной областью не является.

Обычно — да, но просто где-то в этой ветке упоминается именно в таком контексте.

ПК>2) Математические понятия квадрата и прямоугольника не предполагают от них

ПК>никакого поведения, соответственно, эти понятия в программе, наделяющей
ПК>соответствующие объекты поведением, могут использоваться очень ограниченно.

Очень даже предполагают, имхо. Они задают инварианты, которые определяют, в какой степени можно менять свойства экземпляра того или иного понятия.

ПК>3) И да, понятия в программировании далеко не обязательно один-в один

ПК>соответствуют понятиям предметной области.

Но, ведь проблема-то как раз в том, чтобы найти способ как можно более похожего описания.

s>> На самом деле, в математиеских изысканиях, мы оперируем понятиями точно

s>> также, как объектами в программе. Например, в ходе логического
s>> доказательства теоремы мы также "читаем" свойства понятий и также
s>> изменяем их.

ПК>Относительно изменения есть серьезные сомнения...


Если их нигде не изменять (как минимум — задавать), то зачем же их вообще читать?
http://www.lmdinnovative.com (LMD Design Pack)
Re[16]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 02.08.05 14:39
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Gaperton,


G>>> Тем не менее, таки, попрошу дать определение хотя бы "поведение p не

G>>> изменится". Если у нас программа рисовала квадраты... и, вдруг, начала
G>>> рисовать прямоугольники — изминилось или нет её поведение? Почему?

G>> Программа определена в терминах Т. Ее поведение не должно измениться

G>> именно в этих терминах. Это действительно немного путанный момент -
G>> можно мне переформулировать так, чтобы было понятнее?

G>> Если для любого o1 <- S найдется такой o2 <- T, что не будет
G>> существовать такой программы p, которая при замене o1 на o2 способна
G>> определить эту замену, то S является подтипом T.


ПК>Полагаю, более практично говорить соответствии программы своей спецификации,

ПК>при условии, что программа корректна, т.е. учитывает все возможные исходы
ПК>использования T, заданные его спецификацией. Говоря о поведении, Барбара
ПК>Лисков как раз говорит о спецификации и соответствии требованиям.

На мой взгляд это как раз менее практично в данном случае, так как
1) Позволяет развести спекуляции на тему "корректности" или некоректности поведения программ, и влияния разного поведения подтипов на спецификацию. Понятное дело, что спецификация составлена в терминах Т, но эти спекуляции совершенно к делу не относятся. Принимая это во внимание, я бы сказал, такое определение верно, но контринтуитивно.
2) Это определение не конструктивно в том смысле, что не дает прямого способа ("алгоритма") проверить или опровергнуть соответствие ему.
3) Введение понятий специфицкации и корректности в определение можно избежать. Бритва Оккама.
Re[8]: Кто автор?
От: Павел Кузнецов  
Дата: 02.08.05 15:07
Оценка:
stalcer,

> ПК>2) Математические понятия квадрата и прямоугольника не предполагают от них

> ПК>никакого поведения, соответственно, эти понятия в программе, наделяющей
> ПК>соответствующие объекты поведением, могут использоваться очень ограниченно.

> Очень даже предполагают, имхо. Они задают инварианты, которые определяют,

> в какой степени можно менять свойства экземпляра того или иного понятия.

Да, инварианты они определяют. Т.е. они говорят о наборе валидных состояний.
Чем они не наделяют экземпляры понятий, так это возможностью переходить из одного
состояния в другое, т.к. идентифицируют свои экземпляры понятий с тем же, с чем
идентифицируется состояние объекта в программировании. Трансформация квадрата или
прямоугольника приводит к получению нового экземпляра понятия (квадрата
или прямоугольника), а не к изменению существующего.

Т.е., собственно, в математике (по крайней мере, в части, определяющей квадраты
как разновидность прямоугольников) нет изменения. Есть математические объекты,
задаваемые их свойствами. "Два" квадрата, коль скоро доказано, что они обладают
одними и теми же свойствами, -- суть один математический объект. То же в случае
векторов, точек и т.п. Т.е. нет как такового изменения экземпляров, есть их
создание (или выделение, как, пожалуй, более точно выразился Владимир в
соседней подветке).

Скажем, как можно изменить числа "5" или "10"? Для математики квадраты,
прямоугольники, точки, вектора и т.п. в этом смысле -- более-менее то же самое.
Они идентифицируют некоторое значение в множестве возможных.
Программирование же построено поверх этой модели, и добавляет к объекту понятие
identity, которое не зависит от состояния объекта: два объекта, даже находящихся
в одном состоянии, тем не менее, остаются двумя разными объектами.

Т.е., для нашего случая как раз принципиальна разница между программированием
и математикой в определении identity объектов.

> ПК>3) И да, понятия в программировании далеко не обязательно один-в один

> ПК>соответствуют понятиям предметной области.

> Но, ведь проблема-то как раз в том, чтобы найти способ как можно болеепохожего описания.


Не факт.

> s>> На самом деле, в математиеских изысканиях, мы оперируем понятиямиs>> точно также, как объектами в программе. Например, в ходе логического

> s>> доказательства теоремы мы также "читаем" свойства понятий и также
> s>> изменяем их.

> ПК>Относительно изменения есть серьезные сомнения...


> Если их нигде не изменять (как минимум — задавать), то зачем же их вообще

> читать?

Можно говорить не об изменении существущих экземпляров, а о создании новых.
Так, например, происходит в случае "чистого" функционального программирования,
которое в этом смысле как раз достаточно близко к математике.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 02.08.05 15:17
Оценка: +2
Здравствуйте, stalcer, Вы писали:

S>1) ООП придумано, чтобы писать программы в терминах предметной области.

S>2) Принцип подстановки Лисков — один из принципов ООП.
S>3) С точки зрения нашей предметной области (математики) любой квадрат является прямоугольником.
S>4) Вся эта ветка форума показывает, что квадрат от прямоугольника наследовать нельзя, так как нарушается ППЛ.
В пункте 4 ошибка. Его таки можно пронаследовать так, чтобы ППЛ не нарушился, если операции не будут изменять состояния объекта.

S>Налицо явное противоречие. Значит один из пунктов неверный.

S>Подозреваю, нас злостно обманывали в школе и это пункт 3.

S>На самом деле, в математиеских изысканиях, мы оперируем понятиями точно также, как объектами в программе.


Не точно также. Понятие подмножества в математике и понятие "подтипа" в computer scienсe — разные вещи.
1) Абстрактый Тип Данных (АТД) определяется только набором операций над ним, и никоим образом не атрибутами. Операция определяется предусловиями и постусловиями. При этом, у АТД все равно есть множество возможных значений, и множество значений подтипа является подмножеством множества значений типа. Вот это, последнее — единственная общая черта, и это необходимое, но совсем не достаточное условие.
2) А вот это серьезное отличие: у наших объектов есть состояние и модифицирующие операции (нонсенс с точки зрения математики — она вообще под таким углом на проблему не смотрит), и модифицирующие операции у нас являются замкнутыми, т.е. не могут выводить объект из его типа.

В принципе пункта 2 достаточно, чтобы разрешить "явное противоречие". А именно, из того факта, что одно множесто является подмножеством другого, вовсе не следует, что они связаны отношением подтипа. Причина нарушения ППЛ в нашем случае состоит именно в том, что операции изменения размеров не являются замкнутыми — они выводят квадрат из класса квадратов. Как заканчивались наставления самураев по владению техникой меча, это следует внимательно изучить.
Re[17]: Кто автор?
От: Павел Кузнецов  
Дата: 02.08.05 15:29
Оценка: +1
Gaperton,

> 2) Это определение не конструктивно в том смысле, что не дает прямого способа ("алгоритма") проверить или опровергнуть соответствие ему.

> 3) Введение понятий специфицкации и корректности в определение можно избежать. Бритва Оккама.

Боюсь, поворота обсуждения в сторону рассуждений о более точном определении "поведения" избежать будет сложно, т.к., если отталкиваться от твоей трактовки изменения поведения как способности программы определения замены, то многие вполне валидные примеры наследования диагностируемы при замене экземпляра базового класса на унаследованный.

Например:
class Container
{
public:
   virtual void insert(Object);
   virtual void iterate(Callback);
};

class AssociativeOrderedContainer : public Container
{
   . . .
};

очевидно, что ход исполнения программы может различаться в случае ассоциативного упорядоченного контейнера и "произвольного" контейнера, не упорядочивающего элементы, т.к. первый будет всегда итирировать по добавленным объектам в некотором определенном порядке, почти не зависящем от очередности добавления элементов, а второй — скажем, в порядке добавления элементов.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[18]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 02.08.05 15:59
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Gaperton,


>> 2) Это определение не конструктивно в том смысле, что не дает прямого способа ("алгоритма") проверить или опровергнуть соответствие ему.

>> 3) Введение понятий специфицкации и корректности в определение можно избежать. Бритва Оккама.

ПК>Боюсь, поворота обсуждения в сторону рассуждений о более точном определении "поведения" избежать будет сложно, т.к., если отталкиваться от твоей трактовки изменения поведения как способности программы определения замены, то многие вполне валидные примеры наследования диагностируемы при замене экземпляра базового класса на унаследованный.


Да, ты совершенно прав. О диагностировании замены говорить нельзя. Либо надо вводить понятие корректности программы, что строго сделать довольно тяжело (особенно если принять во внимание, что в LSP идет речь о любой программе), либо... Придется говорить об инвариантах базового класса, т.е. взять определение подтипа в том виде, в котором он мне изестен из теории. А именно
1) предусловия перекрытых операций не могут быть строже, чем в типе.
2) постусловия перекрытых операций не могут быть слабее, чем в типе.

Для твоего примера:

Контейнер, операция вставки: pred_base = true, post_base = element принадлежит контейнеру;
Сортированый контейнер, вставка:
pred = pred_base (true),
post = post_base (принадлежность контейнеру) && для последовательности вызовов iterate каждый следующий элемент меньше либо равен предыдущему.
Re[18]: Все еще проще
От: Gaperton http://gaperton.livejournal.com
Дата: 02.08.05 16:10
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Gaperton,


>> 2) Это определение не конструктивно в том смысле, что не дает прямого способа ("алгоритма") проверить или опровергнуть соответствие ему.

>> 3) Введение понятий специфицкации и корректности в определение можно избежать. Бритва Оккама.

ПК>Боюсь, поворота обсуждения в сторону рассуждений о более точном определении "поведения" избежать будет сложно, т.к., если отталкиваться от твоей трактовки изменения поведения как способности программы определения замены, то многие вполне валидные примеры наследования диагностируемы при замене экземпляра базового класса на унаследованный.


Все нормально, моя трактовка рулит (при небольшом уточнении). Только что разобрался, в чем дело.

Надо ограничить множество программ P оперирующих над Т таким образом, чтобы они полагались на инварианты типа Т. Кстати, мне кажется именно это и имеется в виду в LSP.

Для твоего примера с контейнерами — порядок, в котором добавляются элементы в базовый класс должен быть неопределен. Просто обязан. Если в спецификации базового типа "контейнер" сказано, что они лежат там в том порядке, в котором их туда положили, то твой пример наследования с сортированым контейнером безусловно нарушает LSP. И, кстати, определение подтипа, которое я привел в параллельном посте.

А вот если спецификация не покрывает этот аспект, то, извините, и программа (в т.ч. диагностирующая) на порядок закладываться не должна. Сами понимаете. Именно этими инвариантами и предлагается ограничить класс программ P, из которого предлагается брать диагностирующие тип контрпримеры.

Таким образом, мы все-таки можем уйти от использования понятия "корректности".
Re[18]: Кто автор?
От: prVovik Россия  
Дата: 02.08.05 16:30
Оценка: 10 (2) +1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>очевидно, что ход исполнения программы может различаться в случае ассоциативного упорядоченного контейнера и "произвольного" контейнера, не упорядочивающего элементы, т.к. первый будет всегда итирировать по добавленным объектам в некотором определенном порядке, почти не зависящем от очередности добавления элементов, а второй — скажем, в порядке добавления элементов.


Для программы, оперирующей объектами базового типа, поведение объектов подтипа является существенным только когда эта программа знает о существовании подтипов, но в данном случае код нельзя назвать обобщенным. В случае обобщенного кода, поведение подтипов должно быть безразлично, то есть это поведение является черным ящиком. А отличить друг от друга два черных ящика, не заглядывая внутрь их (то есть оставаясь в рамках обобщенного кода) невозможно. А если же ящики недотаточно "черные" (например, дырявые), то и наследование тоже "дырявое"
... << RSDN@Home 1.1.4 @@subversion >>
лэт ми спик фром май харт
Re[19]: Кто автор?
От: Gaperton http://gaperton.livejournal.com
Дата: 02.08.05 16:58
Оценка:
Здравствуйте, prVovik, Вы писали:

Целиком согласен. То же самое, что хотел сказать я, только нормальным человеческим языком.
Re[19]: Кто автор?
От: Павел Кузнецов  
Дата: 02.08.05 17:21
Оценка: 9 (1)
Gaperton,

> Да, ты совершенно прав. О диагностировании замены говорить нельзя. Либо надо вводить понятие корректности программы, что строго сделать довольно тяжело (особенно если принять во внимание, что в LSP идет речь о любой программе), либо...


Забавно, что работы Барбары Лисков, послужившие поводом для начала разговора, "крутятся" именно вокруг понятия корректности программ. В той же работе (ссылки — ниже), где вводится LSP, речь идет именно о доказуемом поведении программы. Собственно, работа как раз посвящена проблеме того, насколько могут отличаться различные реализации, не влияя на корректность программы. Корректность в данном случае интересна в смысле доказуемости соответствия поведения программы ее спецификации. Наследование — лишь один из рассматриваемых аспектов.

Вот конкретная цитата:

The specification describes what the abstraction does, but omits any information about how it is implemented. By omitting such detail, we permit many different implementations. An implementation is correct if it provides the behavior defined by the specification. Correctness can be proved mathematically if the specification is written in a language with precise semantics; otherwise we establish correctness by informal reasoning or by the somewhat unsatisfactory technique of testing. Correct implementations differ from one another in how they work, i.e., what algorithms they use, and therefore they may have different performance. Any correct implementation is acceptable to the caller provided it meets the caller's performance requirements. Note that correct implementations need not be identical to one another; the whole point is to allow implementations to differ, while ensuring that they remain the same where this is important. The specification describes what is important.


И еще, в качестве иллюстрации, совсем недалеко от формулировки LSP:

First, a set is not a subtype of a list nor is the reverse true. If the same element is added to a set twice, the result is the same as if it had been added only once and the element is counted only once in computing the size of the set. However, if the same element is added twice to a list, it occurs in the list twice. Thus a program expecting a list might not work if passed a set; similarly a program expecting a set might not work if passed a list.


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

> Придется говорить об инвариантах базового класса, т.е. взять определение подтипа в том виде, в котором он мне изестен из теории.

>
> <...>
>
> Для твоего примера:
>
> Контейнер, операция вставки: pred_base = true, post_base = element принадлежит контейнеру;
> Сортированый контейнер, вставка:
> pred = pred_base (true),
> post = post_base (принадлежность контейнеру) && для последовательности вызовов iterate каждый следующий элемент меньше либо равен предыдущему.

К этому же, но несколько более формально, приходит и Барбара Лисков в совместной с Жанетт Винг работе "Family Values: A Behavioral Notion of Subtyping". Эта работа формализует, что же именно подразумевалось под "поведением" в работе "Data Abstraction and Hierarchy", которую обычно цитируют, говоря об LSP.

В качестве резюме, можно сказать, что в LSP речь идет не о конкретном реализуемом варианте действий, а о множестве допустимых вариантов действий ("поведение") типа T и его подтипа S. А именно: подтип S не должен реализовывать "поведение" (множество реализуемых вариантов действий), выходящее за рамки "поведения" (множества допустимых вариантов действий) типа T. Допустимое поведения типа T задается его спецификацией, включающей:
  • Инварианты типа, задающие множество допустимых "значений" данного типа (если угодно, множество допустимых состояний его объектов).
  • Пред- и постусловия всех его методов (собственно, это и есть описание "поведения" в терминах Барбары Лисков), включающие, помимо прочего, и потенциально порождаемые исключения.



    Возвращаясь к нашим баранам, т.е. к квадрату и прямоугольнику, если пытаться наследовать квадрат от прямоугольника, то допустимость такого наследования будет определять спецификация "поведения" прямоугольника. В частности, если мутирующих операций в спецификации прямоугольника нет, то такое наследование почти наверняка допустимо.

    Также вполне возможна спецификация типа прямоугольника, имеющего мутирующие операции, такая, что одной из вполне валидных его реализаций будет квадрат. Например, если в числе постусловий функции SetWidth перечислена возможность изменения не только высоты, но и ширины. Или если в прямоугольнике есть функция SetDimensions(int width, int height), для которой сказано, что она может порождать исключение, свидетельствующее о недопустимости заданной комбинации значений.

    Другой вопрос, насколько осмысленно введение подобной абстракции "прямоугольника", если от него все время нужно ждать какой-нибудь "пакости"...
    Posted via RSDN NNTP Server 2.0 beta
  • Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[19]: Все еще проще
    От: Павел Кузнецов  
    Дата: 02.08.05 17:43
    Оценка:
    Gaperton,

    > Все нормально, моя трактовка рулит (при небольшом уточнении). Только что разобрался, в чем дело.

    >
    > Надо ограничить множество программ P оперирующих над Т таким образом, чтобы они полагались на инварианты типа Т. Кстати, мне кажется именно это и имеется в виду в LSP.

    Да, именно поэтому я уточнял твое сообщение таким образом:

    Полагаю, более практично говорить соответствии программы своей спецификации, при условии, что программа корректна, т.е. учитывает все возможные исходы использования T, заданные его спецификацией. Говоря о поведении, Барбара Лисков как раз говорит о спецификации и соответствии требованиям.

    "Полагались на инварианты типа T" — одно из условий, включенных в соответствие спецификации. Где я был не точен, так это в "учитывает все возможные исходы использования T, заданные его спецификацией". Т.е. тут, вроде, все верно, но есть более сильное требование, чем необходимо: намного проще говорить о существовании программы, корректность которой нарушается, при условии, что она учитывает только исходы использования Т, заданные его спецификацией.

    Подробнее см. соседнее сообщение
    Автор: Павел Кузнецов
    Дата: 02.08.05
    .

    > Для твоего примера с контейнерами — порядок, в котором добавляются элементы в базовый класс должен быть неопределен. Просто обязан. Если в спецификации базового типа "контейнер" сказано, что они лежат там в том порядке, в котором их туда положили, то твой пример наследования с сортированым контейнером безусловно нарушает LSP. И, кстати, определение подтипа, которое я привел в параллельном посте.


    Да, согласен. Это замечание лишний раз подчеркивает то, что в LSP речь идет о соответствии спецификации.

    > А вот если спецификация не покрывает этот аспект, то, извините, и программа (в т.ч. диагностирующая) на порядок закладываться не должна. Сами понимаете. Именно этими инвариантами и предлагается ограничить класс программ P, из которого предлагается брать диагностирующие тип контрпримеры.

    >
    > Таким образом, мы все-таки можем уйти от использования понятия "корректности".

    Не уйдем

    Не уйдем, т.к. понятие спецификации вводится именно в ходе попыток доказательства корректности программ, и именно к этой области относятся работы Барбары Лисков. Вне рассуждений о возможности доказательства корректности программы, твоя фраза: "если спецификация не покрывает этот аспект, то, извините, и программа (в т.ч. диагностирующая) на порядок закладываться не должна," — теряет свою силу, т.к. программа должна ограничиваться только информацией о типе, сообщаемой его спецификацией, именно для того, чтобы была возможность доказательства корректности данной программы (т.е. соотвествия ее своей спецификации).

    Подробнее см. упомянутое соседнее сообщение.
    Posted via RSDN NNTP Server 2.0 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[19]: Кто автор?
    От: Павел Кузнецов  
    Дата: 02.08.05 17:46
    Оценка:
    prVovik,

    > ПК> очевидно, что ход исполнения программы может различаться в случае ассоциативного упорядоченного контейнера и "произвольного" контейнера, не упорядочивающего элементы, т.к. первый будет всегда итирировать по добавленным объектам в некотором определенном порядке, почти не зависящем от очередности добавления элементов, а второй — скажем, в порядке добавления элементов.


    > Для программы, оперирующей объектами базового типа, поведение объектов подтипа является существенным только когда эта программа знает о существовании подтипов, но в данном случае код нельзя назвать обобщенным. <...>


    Именно для подведения к необходимости введения понятия спецификации при обсуждении "поведения" в LSP и давался этот пример
    Posted via RSDN NNTP Server 2.0 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[20]: Все еще проще
    От: Gaperton http://gaperton.livejournal.com
    Дата: 02.08.05 18:05
    Оценка: 1 (1)
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Gaperton,


    >> Все нормально, моя трактовка рулит (при небольшом уточнении). Только что разобрался, в чем дело.

    >>
    >> Надо ограничить множество программ P оперирующих над Т таким образом, чтобы они полагались на инварианты типа Т. Кстати, мне кажется именно это и имеется в виду в LSP.

    ПК>Да, именно поэтому я уточнял твое сообщение таким образом:

    ПК>

    ПК>Полагаю, более практично говорить соответствии программы своей спецификации, при условии, что программа корректна, т.е. учитывает все возможные исходы использования T, заданные его спецификацией. Говоря о поведении, Барбара Лисков как раз говорит о спецификации и соответствии требованиям.


    Разница в том, что. Ты говоришь о спецификации программы P, и о корректности P. Я тебя понимаю, и утверждаю, что это сложно, а для наших целей достаточно говорить о спецификации T и о существовании программы p — детектора подтипа, который закладывается только на спецификацию Т. Я утверждаю, что это определение эквивалентно, но проще.

    ПК>"Полагались на инварианты типа T" — одно из условий, включенных в соответствие спецификации. Где я был не точен, так это в "учитывает все возможные исходы использования T, заданные его спецификацией". Т.е. тут, вроде, все верно, но есть более сильное требование, чем необходимо: намного проще говорить о существовании программы, корректность которой нарушается, при условии, что она учитывает только исходы использования Т, заданные его спецификацией.

    То есть ты согласен, что так как я предлагаю — проще? Мы договорились, или я тебя не понял?

    >> Для твоего примера с контейнерами — порядок, в котором добавляются элементы в базовый класс должен быть неопределен. Просто обязан. Если в спецификации базового типа "контейнер" сказано, что они лежат там в том порядке, в котором их туда положили, то твой пример наследования с сортированым контейнером безусловно нарушает LSP. И, кстати, определение подтипа, которое я привел в параллельном посте.


    ПК>Да, согласен. Это замечание лишний раз подчеркивает то, что в LSP речь идет о соответствии спецификации.

    Еще раз, мы с тобой говорим о разных спецификациях. Ты — о P, я — о T. С чем ты согласен?


    >> А вот если спецификация не покрывает этот аспект, то, извините, и программа (в т.ч. диагностирующая) на порядок закладываться не должна. Сами понимаете. Именно этими инвариантами и предлагается ограничить класс программ P, из которого предлагается брать диагностирующие тип контрпримеры.

    >>
    >> Таким образом, мы все-таки можем уйти от использования понятия "корректности".

    ПК>Не уйдем


    ПК>Не уйдем, т.к. понятие спецификации вводится именно в ходе попыток доказательства корректности программ, и именно к этой области относятся работы Барбары Лисков.

    Это не важно в контексте нашего разговора, и я все таки предпочел бы от доказательств корректности уйти. Я читал учебный курс за авторством Лисков касательно доказательства корректности, представляю себе что это такое, и считаю это оффтопом. Как мне кажется, можно сформулировать LSP без необходимости привлекать теории доказательства корректности. И эту формулировку я привел — в качестве доказательства.

    ПК>Вне рассуждений о возможности доказательства корректности программы, твоя фраза: "если спецификация не покрывает этот аспект, то, извините, и программа (в т.ч. диагностирующая) на порядок закладываться не должна," — теряет свою силу, т.к. программа должна ограничиваться только информацией о типе, сообщаемой его спецификацией, именно для того, чтобы была возможность доказательства корректности данной программы (т.е. соотвествия ее своей спецификации).


    Нет, не согласен категорически. Нам нет никакой необходимости доказывать корректность программы P, если мы пользуемся определением LSP в моей формулировке. Если не согласен, объясни пожалуйста — зачем нам этим заниматься.
    Re[21]: Все еще проще
    От: Павел Кузнецов  
    Дата: 02.08.05 18:16
    Оценка:
    Gaperton,

    > Разница в том, что. Ты говоришь о спецификации программы P, и о корректности P. Я тебя понимаю, и утверждаю, что это сложно, а для наших целей достаточно говорить о спецификации T и о существовании программы p — детектора подтипа, который закладывается только на спецификацию Т. Я утверждаю, что это определение эквивалентно, но проще.

    > <...>
    > То есть ты согласен, что так как я предлагаю — проще? Мы договорились, или я тебя не понял?

    Согласен. Договорились. Для того, чтобы просто диагностировать нарушение LSP, корректность программы можно оставить за рамками.

    > Это не важно в контексте нашего разговора, и я все таки предпочел бы от доказательств корректности уйти. Я читал учебный курс за авторством Лисков касательно доказательства корректности, представляю себе что это такое, и считаю это оффтопом. Как мне кажется, можно сформулировать LSP без необходимости привлекать теории доказательства корректности.


    Сформулировать — можно. Только без рассуждении о доказательстве корректности программ не очень понятно, что с LSP делать Впрочем, настаивать не буду: если мы ограничимся самим фактом формулировки LSP, и не будем говорить о том, зачем же мы его формулировали, то да, в формулировку корректность можно не тянуть.
    Posted via RSDN NNTP Server 2.0 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[22]: Зачем нужен Liskov Substitution Principle
    От: Gaperton http://gaperton.livejournal.com
    Дата: 02.08.05 18:25
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Сформулировать — можно. Только без рассуждении о доказательстве корректности программ не очень понятно, что с LSP делать Впрочем, настаивать не буду: если мы ограничимся самим фактом формулировки LSP, и не будем говорить о том, зачем же мы его формулировали, то да, в формулировку корректность можно не тянуть.


    Почему это не будем. Очень даже будем . Ответ прост — соблюдение LSP уменьшает хрупкость и связность системы. Таким образом, он упрощает ее модификацию, и в long term удешевляет разработку.
    Re[23]: Зачем нужен Liskov Substitution Principle
    От: Павел Кузнецов  
    Дата: 02.08.05 18:55
    Оценка: 47 (2)
    Gaperton,

    > ПК> Сформулировать — можно. Только без рассуждении о доказательстве корректности программ не очень понятно, что с LSP делать Впрочем, настаивать не буду: если мы ограничимся самим фактом формулировки LSP, и не будем говорить о том, зачем же мы его формулировали, то да, в формулировку корректность можно не тянуть.


    > Почему это не будем. Очень даже будем . Ответ прост — соблюдение LSP уменьшает хрупкость и связность системы. Таким образом, он упрощает ее модификацию, и в long term удешевляет разработку.


    Логично Вопрос — как достигается эта магия?

    Имхо, благодаря тому, что LSP вносит свой вклад в очерчивание пределов допустимых вариаций в реализациях абстракций, не влияющих на корректность программ (соответствие их своей спецификации), использующих данные абстракции (на основе их спецификаций).

    А именно: при нарушении LSP (т.е. при создании наследников, не соответствующих спецификации базового класса) может произойти нарушение соответствия спецификации программ, использующих базовые классы (на основе их спецификации); при соблюдении LSP могут "сломаться" только те программы, которые были основаны на какой-то дополнительной информации, за пределами спецификации поведения базовых классов (*). Соответственно, без следования LSP, для того, чтобы удостовериться в корректности программы после модификации наследника (или, что то же самое, введении нового наследника), нужно будет проанализировать все места, где используются базовые типы. При соблюдении LSP такой анализ для доказуемо корректных программ проводить не нужно (**). Последнее и есть уменьшение хрупкости (т.е. в нарушении корректности при модификациях) и связности (тут я не уверен в точности русского термина, но, совершенно очевидно, что ты говорил о coupling, а не cohesion, т.к. последнее — "положительная" метрика).

    Грубо говоря, LSP — один из принципов, позволяющих разделить ответственность за корректность работы программ: если был введен наследник, не соответствущий спецификации базового класса, "виноват" автор класса-наследника (или базового класса, неточно составивший спецификацию); если наследник соответствует LSP, но использующая базовый класс программа "сломалась" — "виноват" автор этой программы.

    Собственно, я мог воздержаться от пространных рассуждений, т.к. использование тобой слова "хрупкость", имхо, фактически, автоматом приводит к понятию корректности.


    (*) Трюизм, а сколько копий вокруг прямоугольников и квадратов ломается
    (**) Вот куда я, действительно, не хочу сейчас идти, так это в дебри практического использования доказательств корректности программ, но, к сожалению, упомянуть приходится.
    Posted via RSDN NNTP Server 2.0 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[15]: Кто автор?
    От: gbear Россия  
    Дата: 03.08.05 03:46
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>Программа определена в терминах Т. Ее поведение не должно измениться именно в этих терминах. Это действительно немного путанный момент — можно мне переформулировать так, чтобы было понятнее?

    G>

    G>Если для любого o1 <- S найдется такой o2 <- T, что не будет существовать такой программы p, которая при замене o1 на o2 способна определить эту замену, то S является подтипом T.


    По поводу такой формуллировки у Вас развернулась замечательная дискуссия с Павлом Кузнецовым.

    G>Насчет "определить замену" — на случай, если вы опять не поймете, поясню. Это означает, что вы не сможете написать программу, которая, пользуясь интерфейсом Т, могла бы понять, что ей подпихнули подтип этого Т — S.


    Это — ошибка. Смысл-то как раз в том, что P не должна, как Вы выразились, "понять" что ей "подпихнули" S вместо T.

    G>Или, что то же самое, подтип не должен нарушать инвариантов типа.


    Вот с этим полностью согласен. Необходимое условие behavioural subtyping:

    Если всё множество инвариантов типа T, является подмножеством инвариантов типа S, то S — подтип T.


    Выполнение этого условия означает теоритическую возможность реализации типом S всего поведения типа T... + something extra. И дает подвод для subclassing'га. Возвращаясь к квадрату и прямоугольнику: все множество инвариантов квадрата лежит внутри множества инвариантов прямоугольника.

    Дело за малым — сформулировать условие достаточности . Это нужно, т.к. данное определение не учитывает т.н. state chain предикатов... констрайнов. В том, смысле, что вполне может оказаться что из некоторого множества инвариантов T (B)- не пересекающегося с множеством инвариантов S (A) — невозможно перейти к инварианту из A{}.

    Для пары квадрат/прямоугольник верно утверждение, что из любого инварианта из B{} мы можем перейти к инварианту из A{}.


    G>В контексте этого разговора довольно забавно выглядят ваши слова.

    G>

    G>И лучше бы перед тем как... почитать таки оригинал. Это поможет снять некоторые вопросы. И может быть Вам после этого станет ясно, почему, например, уже в определении ПЛВ нет этих терминов.


    Угу... Потому что если бы Вы таки прочли хотябы тот абзац из которого "выдернуто" определение ППЛ, то, смею надеятся, что Вы бы поняли что речь идёт не более чем о:

    The intuitive idea of a subtype is one whose objects provide all the behavior of objects of another type (the supertype) plus something extra.


    Что в последствии и было сформулировано в досточном условии... в котором нет таких терминов как: программа, неизменно и т.п.

    G>>> Ну да ладно, давайте сюда ваше определение "behavioral subtyping". И давайте посмотрим, каким образом оно сделает вашу ошибку правильным решением.


    G>> Для начала указали бы мне на "ошибку"... а то я, по глупости своей, её так и не увидел.



    G>>И уж тем более, я не увидел определения подтипа. Исключая, ту формуллировку ППЛ, что я привел в предыдущем посте.

    G>http://www.rsdn.ru/Forum/Message.aspx?mid=1290517&amp;only=1
    Автор: Gaperton
    Дата: 25.07.05
    Люди, знакомые с определением, его там увидели, несмотря на то, что я назвал это "наследованием". Ниже по ветке вы можете видеть дискуссию с Олегом на эту тему. Это, кстати, совершенно неважно, разговор не об этом.


    Ещё раз... Сама Лисков не считает сформуллированный ей же принцип подстановки каким-либо условием определяющим наличие behavioural subtyping. Это-то Вам надеюсь понятно?

    G>Впрочем, я разговор заканчиваю, надоело смертельно.


    Мне искренне жаль

    G>Всего доброго.

    Вам того же...

    ---
    С уважением, Сиваков Константин.
    Re[16]: Кто автор?
    От: gbear Россия  
    Дата: 03.08.05 03:55
    Оценка:
    Извиняюсь за ошибку...

    Что в последствии и было сформулировано в досточном условии... в котором нет таких терминов как: программа, неизменно и т.п.


    Следует читать как:

    Что в последствии и было сформулировано в необходимом условии... в котором нет таких терминов как: программа, неизменно и т.п.

    ---
    С уважением, Сиваков Константин.
    Re[21]: Все еще проще
    От: gbear Россия  
    Дата: 03.08.05 04:00
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>Разница в том, что. Ты говоришь о спецификации программы P, и о корректности P. Я тебя понимаю, и утверждаю, что это сложно, а для наших целей достаточно говорить о спецификации T и о существовании программы p — детектора подтипа, который закладывается только на спецификацию Т. Я утверждаю, что это определение эквивалентно, но проще.


    +1. Наконец-то!!! Вот это:

    достаточно говорить о спецификации T и о существовании программы p — детектора подтипа, который закладывается только на спецификацию Т.


    прктически, эквивалентно:

    Let phi(x) be a property provable about objects x of type T. Then phi(y) should be true for objects y of type S where S is a subtype of T.


    Осталось разубедить Вас в том, что нет необходимости рассматривать всё возможное множество phi.

    ---
    С уважением, Сиваков Константин.
    Re[19]: Кто автор?
    От: gbear Россия  
    Дата: 03.08.05 04:07
    Оценка:
    Здравствуйте, prVovik, Вы писали:

    V>Для программы, оперирующей объектами базового типа, поведение объектов подтипа является существенным только когда эта программа знает о существовании подтипов, но в данном случае код нельзя назвать обобщенным. В случае обобщенного кода, поведение подтипов должно быть безразлично, то есть это поведение является черным ящиком. А отличить друг от друга два черных ящика, не заглядывая внутрь их (то есть оставаясь в рамках обобщенного кода) невозможно. А если же ящики недотаточно "черные" (например, дырявые), то и наследование тоже "дырявое"


    +1. Дружно медитируем над двумя "черными" ящиками...


        class S
        {
            private int _size;
    
            public int Size
            {
                get{return _size;}
                set{_size = value;}
            }
    
            public int Area
            {
                get{return (_size * _size);}
            }
        }
    
        class R: S
        {
            private int _width;
    
            public int Height
            {
                get{return base.Size;}
                set{base.Size = value;}
            }
        
            public int Width
            {
                get{return _width;}
                set{_width = value;}
            }
    
            new public int Area
            {
                get{return (base.Size * _width);}
            }
        }


    ----
    С уважением, Сиваков Константин.
    Re[17]: Кто автор?
    От: gbear Россия  
    Дата: 03.08.05 04:11
    Оценка:
    Здравствуйте, AndrewVK, Вы писали:

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


    G>>Тем не менее, для реализации вписаной окружности достаточно реализовать в прямоугольнике привидение его к "квадратному" виду. Т.е. если мы обращаетмся к R.GetInscribedCircle() то R.Width становится равно S.Size.


    AVK>Т.е. делаем функционал, который в постановке задачи отсутствовал. Это называется архитектурной ошибкой.


    1. Наличие Inscribed Circle у прямоугольника возможно только в четко определенном его инварианте. Соответсвенно, если агрегат требует наличия Inscribed Circle (а он именно требует, т.к. работает с прямоугольником через контракт квадрата) нам нужно привести прямоугольник к этому инварианту.

    A>>>В результате получаем семантически непонятный результат. Еще хуже.


    G>>Можно по подробней... о том, что Вы понимаете под "семантически непонятный"?


    AVK>В том, что смысл того функционала, о котором я говорил, применительно к пямоугольнику неясен.


    А, он и не должен быть ясен применительно к прямоугольнику Его применяют к квадрату.

    ---
    С уважением, Сиваков Константин.
    Re[9]: Кто автор?
    От: stalcer Россия  
    Дата: 03.08.05 05:38
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Можно говорить не об изменении существущих экземпляров, а о создании новых.

    ПК>Так, например, происходит в случае "чистого" функционального программирования,
    ПК>которое в этом смысле как раз достаточно близко к математике.

    Ну, хорошо, пусть о создании новых. А что это меняет в моем рассуждении? Просто вместо операции изменения есть операция создания. И тогда она уже не может быть полиморфна для прямоугольников и квадратов. Именно с точки зрения математики.
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[7]: Кто автор?
    От: stalcer Россия  
    Дата: 03.08.05 06:21
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>1) Абстрактый Тип Данных (АТД) определяется только набором операций над ним, и никоим образом не атрибутами.


    Аттрибуты — это операции чтения/записи, также со своими предусловиями и постусловиями.

    G>При этом, у АТД все равно есть множество возможных значений, и множество значений подтипа является подмножеством множества значений типа. Вот это, последнее — единственная общая черта, и это необходимое, но совсем не достаточное условие.


    Это значит лишь то, что либо ООП несовсем адекватно может описывать предметную область, либо в результате занятий программированием к нам приходит более глубокое понимание этой предметной области. Противоречия все равно не может быть.

    G>2) А вот это серьезное отличие: у наших объектов есть состояние и модифицирующие операции (нонсенс с точки зрения математики — она вообще под таким углом на проблему не смотрит), и модифицирующие операции у нас являются замкнутыми, т.е. не могут выводить объект из его типа.


    У понятий предметной области в общем случае все равно есть поведение. И здесь у меня волникают две мысли:

    1) Я могу согласится, что операций изменения в матетатике нет. Ну, дык тогда и причина противоречия налицо: мы вводим в программу операции, которых в предметной области вообще нет. Естественно это может нарушить изначальное отношение обего и частного.
    2) Доказывать какую-нибудь теорему я вполне могу начать со слов: Возмем квадрат S с размером стороны 10. И это будет аналогично программе Sqare s = new Square(10). Разве нет? Так что манипулирование объектами все равно есть.

    G>Причина нарушения ППЛ в нашем случае состоит именно в том, что операции изменения размеров не являются замкнутыми — они выводят квадрат из класса квадратов.


    Вай-вай, как нехорошо. Вот же мое решение
    Автор: stalcer
    Дата: 01.08.05
    (см. код).

    G>А именно, из того факта, что одно множесто является подмножеством другого, вовсе не следует, что они связаны отношением подтипа.


    Повторюсь, это означает лишь то, что в ООП нет адекватных средств для описания предметной области, либо мы недостаточно глубоко понимаем эту предметную область.

    G>Как заканчивались наставления самураев по владению техникой меча, это следует внимательно изучить.


    Да изучали уже вдоль и поперек . Просто хочется понять вот что: может быть LSP, это не тот идеал, к которому следует стремиться, может быть он именно такой за неимением лучшего решения? Именно из-за недостаточно глубокого понимания основ окружающего нас мира.
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[18]: Кто автор?
    От: AndrewVK Россия http://blogs.rsdn.org/avk
    Дата: 03.08.05 08:00
    Оценка:
    Здравствуйте, gbear, Вы писали:

    G>1. Наличие Inscribed Circle у прямоугольника возможно только в четко определенном его инварианте. Соответсвенно, если агрегат требует наличия Inscribed Circle (а он именно требует, т.к. работает с прямоугольником через контракт квадрата) нам нужно привести прямоугольник к этому инварианту.


    Кому нужно? Мне не нужно. Мне вобще не нужна эта операция у прямоугольника. Ни у какого.

    AVK>>В том, что смысл того функционала, о котором я говорил, применительно к пямоугольнику неясен.


    G>А, он и не должен быть ясен применительно к прямоугольнику Его применяют к квадрату.


    Что и требовалось доказать.
    ... << RSDN@Home 1.2.0 alpha rev. 599>>
    AVK Blog
    Re[8]: Кто автор?
    От: NotGonnaGetUs  
    Дата: 03.08.05 12:29
    Оценка:
    Здравствуйте, stalcer, Вы писали:

    G>>Причина нарушения ППЛ в нашем случае состоит именно в том, что операции изменения размеров не являются замкнутыми — они выводят квадрат из класса квадратов.


    S>Вай-вай, как нехорошо. Вот же мое решение
    Автор: stalcer
    Дата: 01.08.05
    (см. код).



    Какая отличная каша получается, если сделать вид, что квадрат и прямоугольник существуют сами по себе, не зависимо от задачи, вызвавшей их к жизни

    Например, создавая Rectangle и выстявляя для него размер 100, 100 мы тем самым создаём тотже самый объект, что и квадрат со стороной 100, так?
    Почему же тогда, эти два одинаковых объекта имеют разные методы для работы с ними? (Добавим к квадрату операцию вычисления радиуса вписанной окружности, а прямоугольнику — увеличение одной из сторон в к раза, а другой в 1/к раз).
    Re[19]: Кто автор?
    От: gbear Россия  
    Дата: 03.08.05 12:36
    Оценка:
    Здравствуйте, AndrewVK, Вы писали:

    G>>А, он и не должен быть ясен применительно к прямоугольнику Его применяют к квадрату.


    AVK>Что и требовалось доказать.


    Доказать-то как раз требывалось наличие у квадрата поведения, не реализуемого прямоугольником. Наличие такого поведение означало бы отсутсвие отношения тип/подтип в терминах behavioural subtyping.

    ---
    С уважением, Сиваков Константин.
    Re[20]: Кто автор?
    От: Павел Кузнецов  
    Дата: 03.08.05 12:39
    Оценка: +3
    gbear,

    g>
     g>     class S
     g>     {
     g>         private int _size;
    
     g>         public int Size
     g>         {
     g>             get{return _size;}
     g>             set{_size = value;}
     g>         }
    
     g>         public int Area
     g>         {
     g>             get{return (_size * _size);}
     g>         }
     g>     }
     g>


    Т.е. одним из следствий удвоения Size является учетверение Area. Так? (*)

    Если не так, то приведи, пожалуйста, спецификацию Size и Area. В частности,
    в той части, где описана связь между ними.

    g>
     g>     class R: S
     g>     {
     g>         private int _width;
    
     g>         public int Height
     g>         {
     g>             get{return base.Size;}
     g>             set{base.Size = value;}
     g>         }
    
     g>         public int Width
     g>         {
     g>             get{return _width;}
     g>             set{_width = value;}
     g>         }
    
     g>         new public int Area
     g>         {
     g>             get{return (base.Size * _width);}
     g>         }
     g>     }
     g>


    Если ответ на (*) положительный, то, очевидно, R изменяет поведение S.

    Если ответ на (*) отрицательный, то, вообще, неясно, какой смысл здесь
    что-либо наследовать: через S с объектами R ничего осмысленного сделать
    не выйдет, т.к. Size и Area, по сути -- "вещи в себе".
    Posted via RSDN NNTP Server 2.0 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[10]: Кто автор?
    От: Павел Кузнецов  
    Дата: 03.08.05 12:47
    Оценка:
    stalcer,

    s> Ну, хорошо, пусть о создании новых. А что это меняет в моем рассуждении?

    s> Просто вместо операции изменения есть операция создания. И тогда она уже
    s> не может быть полиморфна для прямоугольников и квадратов. Именно с точки
    s> зрения математики.

    Меняется то, что в случае создания для операций, выводящих за диапазон допустимых
    значений одного типа, мы вполне можем создавать новые объекты другого типа.
    class Rectangle
    {
    public:
      Rectangle(int w, int h);
      int width() const;
      int height() const;
    };
    
    Rectangle set_width( Rectangle const&, int width );
    Rectangle set_height( Rectangle const&, int height );
    
    class Square : public Rectangle
    {
    public:
      Square(int s);
    };

    В этом случае все более-менее нормально.

    Но вот если допустить именно мутирующие операции, то твое рассуждение:

    На самом деле, в математиеских изысканиях, мы оперируем понятиями точно также, как объектами в программе.

    будет неверным.
    Posted via RSDN NNTP Server 2.0 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[3]: Кто автор?
    От: Трурль  
    Дата: 03.08.05 13:43
    Оценка: +1
    Здравствуйте, Gaperton, Вы писали:

    G>Вот определение наследования:

    G>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что
    G>1) он является экземпляром А (B подмножество А)
    G>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).

    Теоретики различают отношение наследования и отношение "тип-подтип" ("is-a"). Наследование означает просто добавление/модификацию методов/свойств. То есть, квадрат вполне может наследовать прямоугольнику (равно как и наоборот), хотя не является подтипом.
    Re[22]: Все еще проще
    От: Gaperton http://gaperton.livejournal.com
    Дата: 03.08.05 14:00
    Оценка:
    Здравствуйте, gbear, Вы писали:

    G>Осталось разубедить Вас в том, что нет необходимости рассматривать всё возможное множество phi.

    Интересно, и как же вы это сделаете?
    Re[23]: Все еще проще
    От: Трурль  
    Дата: 03.08.05 14:08
    Оценка: 6 (1) :)
    Здравствуйте, Gaperton, Вы писали:

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


    G>>Осталось разубедить Вас в том, что нет необходимости рассматривать всё возможное множество phi.

    G>Интересно, и как же вы это сделаете?

    В качестве первого шага предлагаю ограничится подмножеством вычислимых phi.
    Re[8]: Кто автор?
    От: Gaperton http://gaperton.livejournal.com
    Дата: 03.08.05 14:25
    Оценка:
    Здравствуйте, stalcer, Вы писали:

    G>>Как заканчивались наставления самураев по владению техникой меча, это следует внимательно изучить.


    S>Да изучали уже вдоль и поперек . Просто хочется понять вот что: может быть LSP, это не тот идеал, к которому следует стремиться, может быть он именно такой за неимением лучшего решения? Именно из-за недостаточно глубокого понимания основ окружающего нас мира.


    Ничего лучше ООП для структурирования программ в императивных языках не придумано, а в ООП от LSP никуда не деться. Хотите стремиться к другому идеалу? Да ради бога, есть две альтернативы. Обе — не так чтобы очень.
    1) Динамические языки, например JavaScript. Там вам во многих случаях не понадобится наследование, и вместе с ним уйдет LSP. Хотя до конца вы от наследования не избавитесь.
    2) Декомпозиция программы при помощи потоков. Совершенно ортогональный ООП метод, в принципе. Никаких объектов, наследования и LSP, при этом такая же выразительная сила.
    Re[16]: Кто автор?
    От: Gaperton http://gaperton.livejournal.com
    Дата: 03.08.05 16:50
    Оценка:
    Здравствуйте, gbear, Вы писали:

    G>Это — ошибка. Смысл-то как раз в том, что P не должна, как Вы выразились, "понять" что ей "подпихнули" S вместо T.


    Это — не ошибка. Я взял двойное отрицание. a == !!a. Читайте внимательнее, это одно и то же.

    G> Возвращаясь к квадрату и прямоугольнику: все множество инвариантов квадрата лежит внутри множества инвариантов прямоугольника.


    А вот это — ошибка. Инвариант квадрата: Width == Height. У прямоугольника нет такого инварианта.
    Вот еще один инвариант квадрата: Area == Width^2 == Height^2. Для прямоугольника не выполняется. Это если говорить о геометрических фигурах.

    А теперь о вашем решении (последняя попытка объяснить — ничего нового я вам сказать больше не смогу): Area — инвариант метода S::get_Size (он не меняет площадь, что совершенно естественно и ожидаемо для длины ребра квадрата), но он не является инвариантом его реализации в подклассе R::get_Size. Нарушение этого инварианта будет видимо пользователю S. При этом, исключать это из спецификации S нельзя — с какой стати площадь квадрата должна меняться при попытке узнать длину стороны?

    Вот и все. Вы нарушаете принцып Лисков, определение подтипа и вообще все, что можно нарушить. Постусловие метода R::get_Size получается слабее, чем в базовом классе (инвариант метода преобразуется в пару предусловие — постусловие: S::get_Size true -> Area_pred==Area_post==result^2, в то время как R::get_Size true -> Area_post == result^2).
    Re[9]: Кто автор?
    От: stalcer Россия  
    Дата: 04.08.05 05:45
    Оценка:
    Здравствуйте, NotGonnaGetUs, Вы писали:

    NGG>Например, создавая Rectangle и выстявляя для него размер 100, 100 мы тем самым создаём тотже самый объект, что и квадрат со стороной 100, так?


    Не так .
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[9]: Кто автор?
    От: stalcer Россия  
    Дата: 04.08.05 05:55
    Оценка:
    Здравствуйте, NotGonnaGetUs, Вы писали:

    NGG>Добавим к квадрату операцию вычисления радиуса вписанной окружности, а прямоугольнику — увеличение одной из сторон в к раза, а другой в 1/к раз.


    Ну и если очень хочется:

    class Rectangle
    {
        public int Width  
        {
            get { return _width; }
        }
        public int Height
        {
            get { return _height; }
        }
        public virtual void SetBounds(int width, int height)
        {
            _width  = width;
            _height = height;
        }
        public virtual ChangeDims(double k)
        {
            _width  = (int)(_width * k);
            _height = (int)(_height / k);
        }
        
        private int _width;
        private int _height;
    }
    
    class Square: Rectangle
    {
        public override void SetBounds(int width, int height)
        {
            if (width != height)
                throw Exception("...");
                
            base.SetBounds(width, height);
        }
        public override ChangeDims(double k)
        {
            if (k != 1)
                throw Exception("...");
        }
        public double GetIncircleRadius() { ... }
    }


    Причем, только, здесь "операция вычисления радиуса вписанной окружности", которая вообще может не быть виртуальной, по твоему условию ?
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[9]: Кто автор?
    От: stalcer Россия  
    Дата: 04.08.05 06:08
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>Ничего лучше ООП для структурирования программ в императивных языках не придумано.


    Дык я и предлагаю подумать. Смотреть в корень, так сказать.

    G>1) Динамические языки, например JavaScript. Там вам во многих случаях не понадобится наследование, и вместе с ним уйдет LSP. Хотя до конца вы от наследования не избавитесь.


    Проблему прямоугольника и квадрата это никак не решает.

    G>2) Декомпозиция программы при помощи потоков. Совершенно ортогональный ООП метод, в принципе. Никаких объектов, наследования и LSP, при этом такая же выразительная сила.


    Посмотрю .
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[10]: Кто автор?
    От: NotGonnaGetUs  
    Дата: 04.08.05 06:53
    Оценка:
    Здравствуйте, stalcer, Вы писали:

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


    NGG>>Например, создавая Rectangle и выстявляя для него размер 100, 100 мы тем самым создаём тотже самый объект, что и квадрат со стороной 100, так?


    S>Не так .



    Как это не так?

    Квадрат получился? Получился.
    Имею право вычислить радиус? Имею.

    Но не могу, т.к. он прямоугольник

    Маленький оффтоп:

    Нравится кидать эксепшены, тогда давай и методы квадрата перетащим в прямоугольник, будем там кидать ошибки
    А что бы не заморачиваться (с радиусом, с тем что квадрат это не квадрат), лучше совсем не станем вводить "квадрат" как самостоятельный класс
    Re[9]: Кто автор?
    От: stalcer Россия  
    Дата: 04.08.05 06:53
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>Ничего лучше ООП для структурирования программ в императивных языках не придумано.


    Мне, например, больше нравится такой подход:

    Есть базовый класс A, со своей спецификацией, со своими инвариантами. Есть некая гипотетическая программа P, которая умеет работать с объектами класса A. И есть некий наследник B: A.

    Объекты наследника должны формировать подмножество множества объектов предка с точки зрения предметной области. Несмотря на то, что SLP может при этом нарушаться.
    Операции в наследнике не дают вывести его из множества объектов наследника.
    А вот инварианты могут изменяться.

    Тогда эта программа P, при подсовывании ей объекта класса B, должна либо отработать, либо выбросить исключительную ситуацию.

    Исключительную ситуацию, естественно, будет в конечном счете выбрасывать переопределенная в классе B операция, которую по ходу дела вызывает программа P.

    При таком подходе сохраняется разделение ответственности:

    — Класс A не должен знать ни об особенностях класса B, ни о программе P.
    — Программа P знает об A, так как изначально предназначена для работы с ним, но не должна знать о B.
    — Класс B не обязан знать о программе P.
    — Некая подсистема X , использующая P и не использующая объекты B, не знает об особенностях B и не может получить ошибку вызванную этими особенностями.
    — Некая подсистема X, использующая P и использующая объекты B, знает об особенностях B и готова получить ошибку вызванную этими особенностями.

    Вопрос: как писать программы (P), устойчивые к таким исключительным ситуациям.



    И второй момент. Никто еще не отменял эволюционность. В том числе и эволюционное познание предметной области.

    Поэтому, если в ходе создания наследников от класса TStream, вдруг обнаруживается, что нектороые потоки бывают ReadOnly, например, TFileStream, то нет ничего плохого, чтобы это только что открытое свойство предметной области ввести в интерфейс базового класса.

    То есть независимости предка от его наследников в общем случае нет. Ведь какое-либо множество объектов какого-либо класса предметной области, рассматриваемое нами при проектировании класса в программе, естественным образом включает в себя все возможные подмножества себя (этого множества).
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[11]: Кто автор?
    От: stalcer Россия  
    Дата: 04.08.05 07:03
    Оценка:
    Здравствуйте, NotGonnaGetUs, Вы писали:

    NGG>Квадрат получился? Получился.


    Если квадрат получился, то, конечно, ты прав. И скорее всего отдельного класса для квадрата вводить не нужно.

    Но с моей точки зрения это не квадрат, так как он отличается по поведению. Например, его запросто можно вывести из множества квадратов изменением, скажем, длины. А настоящий квадрат — нельзя.
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[10]: Кто автор?
    От: Gaperton http://gaperton.livejournal.com
    Дата: 04.08.05 12:37
    Оценка: :)
    Здравствуйте, stalcer, Вы писали:

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


    G>>Ничего лучше ООП для структурирования программ в императивных языках не придумано.


    S>Мне, например, больше нравится такой подход:


    S>Есть базовый класс A, со своей спецификацией, со своими инвариантами. Есть некая гипотетическая программа P, которая умеет работать с объектами класса A. И есть некий наследник B: A.


    S>Объекты наследника должны формировать подмножество множества объектов предка с точки зрения предметной области. Несмотря на то, что SLP может при этом нарушаться.

    S>Операции в наследнике не дают вывести его из множества объектов наследника.
    S>А вот инварианты могут изменяться.

    S>Вопрос: как писать программы (P), устойчивые к таким исключительным ситуациям.

    Никак. В этом его слабая сторона.
    Re[10]: Кто автор?
    От: Gaperton http://gaperton.livejournal.com
    Дата: 04.08.05 12:45
    Оценка: +1
    Здравствуйте, stalcer, Вы писали:

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


    G>>Ничего лучше ООП для структурирования программ в императивных языках не придумано.


    S>Дык я и предлагаю подумать. Смотреть в корень, так сказать.


    В этой ветке как минимум трижды упоминалось, что именно надо сделать, чтобы при наследовании не нарушился LSP. Вы и я далеко не первые, кто над этим думал, понимаете? Вот ответ — в очередной раз:

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

    G>>1) Динамические языки, например JavaScript. Там вам во многих случаях не понадобится наследование, и вместе с ним уйдет LSP. Хотя до конца вы от наследования не избавитесь.


    S>Проблему прямоугольника и квадрата это никак не решает.

    Решает на счет раз. В корень смотрите , и все будет ок.

    В JavaScript вы можете добавлять и удалять методы на лету, т. е. фактически вы можете реализовать изменение типа для объекта. При этом, вам вообще не нужен базовый класс, так как вызовы диспетчеризуются динамически. А нет базового класса, нет и LSP. Как ни странно, объекты при этом есть, и полиморфизм остается.
    Re[12]: Кто автор?
    От: NotGonnaGetUs  
    Дата: 04.08.05 13:02
    Оценка:
    Здравствуйте, stalcer, Вы писали:

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


    NGG>>Квадрат получился? Получился.


    S>Если квадрат получился, то, конечно, ты прав. И скорее всего отдельного класса для квадрата вводить не нужно.


    S>Но с моей точки зрения это не квадрат, так как он отличается по поведению. Например, его запросто можно вывести из множества квадратов изменением, скажем, длины. А настоящий квадрат — нельзя.


    Я о том же. В одной задаче выделять квадрат нужно, и это можно сделать выделив общего наследника для этих объектов (с общими методами и без методов модификации размеров), в другой — не нужно абсолютно.
    Re[17]: Кто автор?
    От: gbear Россия  
    Дата: 05.08.05 03:18
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>>Это — ошибка. Смысл-то как раз в том, что P не должна, как Вы выразились, "понять" что ей "подпихнули" S вместо T.


    G>Это — не ошибка. Я взял двойное отрицание. a == !!a. Читайте внимательнее, это одно и то же.


    Действительно так. Примите мои извинения. В этом месте я был неправ.

    G>> Возвращаясь к квадрату и прямоугольнику: все множество инвариантов квадрата лежит внутри множества инвариантов прямоугольника.


    G>А вот это — ошибка. Инвариант квадрата: Width == Height. У прямоугольника нет такого инварианта.


    Хм... Т.е. для прямоугольника, состояние когда его ширина равна высоте является не допустимым?!

    G>Вот еще один инвариант квадрата: Area == Width^2 == Height^2. Для прямоугольника не выполняется. Это если говорить о геометрических фигурах.


    Вообще говоря... Для квадрата понятия ширина/высота избыточны... для него оперируют другим понятием — размер стороны. И этот инвариант квадрата "укладывается" в инварианты прямогугольника, находящегося в сотоянии Width == Height. Если, конечно, допустить что такое состояние для прямоугольника является допустимым.

    G>А теперь о вашем решении (последняя попытка объяснить — ничего нового я вам сказать больше не смогу): Area — инвариант метода S::get_Size (он не меняет площадь, что совершенно естественно и ожидаемо для длины ребра квадрата), но он не является инвариантом его реализации в подклассе R::get_Size. Нарушение этого инварианта будет видимо пользователю S. При этом, исключать это из спецификации S нельзя — с какой стати площадь квадрата должна меняться при попытке узнать длину стороны?


    Ок. Смотрим на два черных ящика
    Автор: gbear
    Дата: 03.08.05
    .

    G>Вот и все. Вы нарушаете принцып Лисков, определение подтипа и вообще все, что можно нарушить. Постусловие метода R::get_Size получается слабее, чем в базовом классе (инвариант метода преобразуется в пару предусловие — постусловие: S::get_Size true -> Area_pred==Area_post==result^2, в то время как R::get_Size true -> Area_post == result^2).


    Хорошо, хорошо... С этим согласен. Наличие такого постусловия в контракте квадрата, бесусловно, делает такой вариант невалидным. Другое дело, что этот вариант не едиственный.

    ---
    С уважением, Сиваков Константин.
    Re[18]: Кто автор?
    От: Павел Кузнецов  
    Дата: 05.08.05 03:38
    Оценка:
    gbear,

    > G>> Возвращаясь к квадрату и прямоугольнику: все множество инвариантов квадрата лежит внутри множества инвариантов прямоугольника.

    >
    > G> А вот это — ошибка. Инвариант квадрата: Width == Height. У прямоугольника нет такого инварианта.
    >
    > Хм... Т.е. для прямоугольника, состояние когда его ширина равна высоте является не допустимым?!

    Инвариант — ограничение, накладываемое на множество состояний, которые могут принимать объекты данного класса. У квадрата есть ограничение, заключающееся в том, что для всех объектов ширина должна равняться высоте. У прямоугольника такого ограничения (инварианта) нет.
    Posted via RSDN NNTP Server 1.9
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[21]: Кто автор?
    От: gbear Россия  
    Дата: 05.08.05 03:55
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Т.е. одним из следствий удвоения Size является учетверение Area. Так? (*)


    Хм... Хороший вопрос. Для квадрата — да. Но и для, прямоугольника с шириной равной высоте, тоже, да.

    ПК>Если ответ на (*) положительный, то, очевидно, R изменяет поведение S.


    Поведение S, если вы заметили, — неизменно. R лишь "специализирует" (уточняет) расчет площади. Что вполне логично, т.к. ширина == высоте (или, другимим словами, Area == Windth^2 == Height^2) (1) — лишь один из инвариантов прямоугольника.

    ПК>Если ответ на (*) отрицательный, то, вообще, неясно, какой смысл здесь

    ПК>что-либо наследовать:

    Смысл есть... хотя бы такой:

    Пусть есть класс, реализующий поведение квадрата. Какое именно, не суть важно. Т.к. квадрат — один из инвариантов прямоугольника, то нет смысла в классе, реализующем прямоугольник, повторять реализации поведения квадрата для инварианта (1). Я могу унаследовать это поведение от квадрата, и до реализовать поведение прямоугольника выходящее за рамки инварианта (1). Все за чем нужно следить — это, чтобы применение унаследованного поведения (в смысле, как например, вызов R.Area()) в случае если прямоугольник не находится в состоянии (1), либо приводило прямоугольник в это состояние, либо было уточнено.

    ПК>через S с объектами R ничего осмысленного сделать

    ПК>не выйдет, т.к. Size и Area, по сути -- "вещи в себе".

    Как бы это сказать-то... Это совершенно нормально! Смысл наследования не в полиморфности... она (полиморфность) вовсе не обязана возникать в следсвиии наследования (inheritance, generalization). Если нам нужна именно полиморфность поведения, то мы используем совсем друго отношение — а именно, реализацию (implementation).

    Смысл наследования, как раз в том, чтобы взять готовое поведение и расширить его. Для программы, выраженой в терминах суперкласса (для агрегата суперкласса, если хотите) — это гарантированно будет означать, неизменность — во всех смыслах — его поведения. Что и имела ввиду г-жа Лисков. Рассуждая о полиморфности, она прямо указывает:

    Whenever there are related types in a program there is likely to be polymorphism. This is certainly the case when the relationship is indicated by the need for a polymorphic module. Even when the relationship is identified in advance, however, polymorphism is likely. In such a case the supertype is often virtual: it has no objects of its own, but is simply a placeholder in the hierarchy for the family of related types. In this case, any module that uses the supertype is polymorphic. On the other hand, if the supertype has objects of its own, some modules might use just it and none of its subtypes.


    ---
    С уважением, Сиваков Константин.
    Re[19]: Кто автор?
    От: gbear Россия  
    Дата: 05.08.05 04:02
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Инвариант — ограничение, накладываемое на множество состояний, которые могут принимать объекты данного класса. У квадрата есть ограничение, заключающееся в том, что для всех объектов ширина должна равняться высоте. У прямоугольника такого ограничения (инварианта) нет.


    Спасибо за поправку... занесло. Конечно, говоря "инвариант" я имею ввиду, лишь допустимое состояние. Извиняюсь... В этом
    Автор: gbear
    Дата: 05.08.05
    , ответе, тоже самое.

    ---
    С уважением, Сиваков Константин.
    Re[22]: Кто автор?
    От: Павел Кузнецов  
    Дата: 05.08.05 04:57
    Оценка:
    gbear,

    > ПК> Т.е. одним из следствий удвоения Size является учетверение Area. Так? (*)

    >
    > Хм... Хороший вопрос. Для квадрата — да. Но и для, прямоугольника с шириной равной высоте, тоже, да.

    Нет. Если у прямоугольника ширина была равна высоте, и ширину удвоили без изменения высоты, площадь не учетверится, а удвоится. Если же высота прямоугольника сама собой будет изменяться при изменении ширины, то мы получим нарушения в работе функций, рассчитывающих на "разумность" поведения прямоугольников.

    > ПК> Если ответ на (*) положительный, то, очевидно, R изменяет поведение S.

    >
    > Поведение S, если вы заметили, — неизменно. R лишь "специализирует" (уточняет) расчет площади. Что вполне логично, т.к. ширина == высоте (или, другимим словами, Area == Windth^2 == Height^2) (1) — лишь один из инвариантов прямоугольника.

    Одно из допустимых состояний прямоуголника, но не его инвариант. Квадрат содержит другие инварианты, чем прямоугольник.

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


    Если посмотреть на код, приведенный выше, то можно обнаружить, что "прямоугольник" вообще не использует поведение "квадрата", а просто-напросто разделяет с ним одно из полей. Поведение же (т.е. в формализме Барбары Лисков инварианты и набор пред-/постусловий методов) у этих классов различаются, не укладываясь в требования, выдвигаемые к отношению is-a subtype of. Причем, в обе стороны: ни множество инвариантов (ограничений) квадрата не является подмножеством инвариантов (ограничений) прямоугольника, ни наоборот.

    В частности, для любого объекта квадрата постусловием изменения Size является учетверение Area. Применительно к прямоугольникам этого не происходит никогда.

    И наоборот, для любого объекта прямоугольника, заданного кодом выше по ветке, постусловием изменения Size является удвоение Area. Применительно к квадратам этого не происходит никогда.

    Если же ты, все таки, говоришь о наследовании реализации, то какое к этому вообще отношение имеет LSP? Да и, вообще, цитируемые работы Барбары Лисков, в которых речь идет не о наследовании реализации, а об отношении supertype-subtype, которое к наследованию реализации не относится... В общем, похоже, я окончательно потерял нить твоих рассуждений.
    Posted via RSDN NNTP Server 1.9
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[11]: Кто автор?
    От: stalcer Россия  
    Дата: 05.08.05 05:27
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    S>>Проблему прямоугольника и квадрата это никак не решает.

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

    Да, об этом то я и не подумал.
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[11]: Кто автор?
    От: stalcer Россия  
    Дата: 05.08.05 05:31
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>Достаточно возвращать измененную копию объекта вместо изменения самого объекта, и все — вы без проблем моделируете вашу математику, не нарушая принцип Лисков.


    Думаю, что это весьма ограниченное и не универсальное решение. Во многих случаях, имхо, не прокатит.
    Вот если действительно иметь механизм изменения типа объекта...
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[11]: Кто автор?
    От: stalcer Россия  
    Дата: 05.08.05 05:47
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>Никак. В этом его слабая сторона.


    Ну, почему.
    — Во-первых, научились же писать программы, устойчивые к исключениям в плане утечек памяти (смарт поинтеры и т.п.).
    — Во-вторых, я же отметил, что во многих случаях вся иерархия наследования принадлежит одной подсистеме, которую мы знаем, и знаем особенности поведения наследников. В особо критических случаях, если новый наследник уж совсем не укладывается в инварианты своего предка, то нужно рефакторить предка, например, добавляя в него новые методы (типа TStream.IsReadOnly). И соответственно рефакторить все зависимые от предка программы.
    — В-третьих, абстрактных базовых классов, которые действительно предназначены для наследования и для которых заранее не известны гипотетические наследники, в программе не так уж и много. И в контракт таких классов я обычно неявно добавляю следующее: Любой метод может выкинуть исключительную ситуацию.
    http://www.lmdinnovative.com (LMD Design Pack)
    Re[18]: Кто автор?
    От: Gaperton http://gaperton.livejournal.com
    Дата: 05.08.05 12:29
    Оценка:
    Здравствуйте, gbear, Вы писали:

    G>>А вот это — ошибка. Инвариант квадрата: Width == Height. У прямоугольника нет такого инварианта.

    G>Хм... Т.е. для прямоугольника, состояние когда его ширина равна высоте является не допустимым?!
    Вам уже ответил Павел, но повторюсь на всякий случай.

    Инвариантом в данном случае называется некое свойство, выполняющееся для всех элементов множества. Для всех квадратов это верно всегда. Для прямоугольника это допустимо (бывает), но вообще говоря не верно (есть много прямоугольников, для которых это не так, так что это не инвариант).

    G>>А теперь о вашем решении (последняя попытка объяснить — ничего нового я вам сказать больше не смогу): Area — инвариант метода S::get_Size (он не меняет площадь, что совершенно естественно и ожидаемо для длины ребра квадрата), но он не является инвариантом его реализации в подклассе R::get_Size. Нарушение этого инварианта будет видимо пользователю S. При этом, исключать это из спецификации S нельзя — с какой стати площадь квадрата должна меняться при попытке узнать длину стороны?


    G>Ок. Смотрим на два черных ящика
    Автор: gbear
    Дата: 03.08.05
    .


    По этому пункту совершенно солгласен с ПК. Не виду смысла так наследовать, так как при обращении к прямоугольнику по интерфейсу квадрата он ведет себя весьма странным образом. Т.е. S у вас — совсем никакой не квадрат.

    Формально — нарушается инвариант бызового класса get_Size^2==get_Area, являющийся неотлемлемой частью поведения квадрата. А если вы выкинете этот инвариант из спецификации S, чтобы избежать противоречий, то S перестанет быть квадратом вообще, и станет моделировать произвольную параметрическую фигуру, задаваемую одним параметром. Причем, реализация по умолчанию будет как у квадрата, но сторонний код не должен на это закладываться, и должен работать с типом S как с произвольной однопараметрической фигурой. Более того, этот параметр Size лишен наглядного смысла — площадь от него зависит то квадратично, то линейно...

    G>>Вот и все. Вы нарушаете принцып Лисков, определение подтипа и вообще все, что можно нарушить. Постусловие метода R::get_Size получается слабее, чем в базовом классе (инвариант метода преобразуется в пару предусловие — постусловие: S::get_Size true -> Area_pred==Area_post==result^2, в то время как R::get_Size true -> Area_post == result^2).


    G>Хорошо, хорошо... С этим согласен. Наличие такого постусловия в контракте квадрата, бесусловно, делает такой вариант невалидным. Другое дело, что этот вариант не едиственный.


    Как вы не поймете. Вы можете пытаться сколько угодно, и любой ваш вариант будет некорректен (кроме варианта с копирующими const методами), просто потому, что сделать так невозможно, и этот факт доказан. Если вы уверены в себе, я предлагаю вам очередную попытку за 50 долларов.
    Re[24]: Все еще проще
    От: Gaperton http://gaperton.livejournal.com
    Дата: 05.08.05 13:19
    Оценка:
    Здравствуйте, Трурль, Вы писали:

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


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


    G>>>Осталось разубедить Вас в том, что нет необходимости рассматривать всё возможное множество phi.

    G>>Интересно, и как же вы это сделаете?

    Т>В качестве первого шага предлагаю ограничится подмножеством вычислимых phi.

    А что, невычислимое phi у нас может являеться доказуемым свойством? Пример в студию
    Re[25]: Все еще проще
    От: raskin Россия  
    Дата: 05.08.05 14:29
    Оценка:
    Gaperton wrote:
    > Т>В качестве первого шага предлагаю ограничится подмножеством вычислимых
    > /phi/.
    > А что, невычислимое phi у нас может являеться /доказуемым свойством/?
    > Пример в студию

    Свойство программы останавливаться. Его можно доказать протоколом
    работы. Но оно невычислимо.
    Posted via RSDN NNTP Server 2.0 beta
    Re[26]: Все еще проще
    От: Gaperton http://gaperton.livejournal.com
    Дата: 05.08.05 16:06
    Оценка:
    Здравствуйте, raskin, Вы писали:

    R>Gaperton wrote:

    >> Т>В качестве первого шага предлагаю ограничится подмножеством вычислимых
    >> /phi/.
    >> А что, невычислимое phi у нас может являеться /доказуемым свойством/?
    >> Пример в студию

    R>Свойство программы останавливаться. Его можно доказать протоколом

    R>работы. Но оно невычислимо.

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

    Ограничивать их множеством вычислимых — нахрен не нужно, так как нам не нужно уметь их вычислять. Если мы знаем, что свойство Х всегда выполняется на классе объектов Y, то факт наличия этого свойства уже доказан, все.

    Мы же не систему поиска вывода пишем (что, кстати, в случае исчисления предикатов сделать невозможно — оно полуразрешимо, т.е. там существуют утверждения с бесконечным выводом, как следствие — проблема вывода эквивалентна проблеме останова ).

    Так что не смотря на блестящий пример, предложение Трурля отклоняется.
    Re[27]: Все еще проще
    От: raskin Россия  
    Дата: 05.08.05 17:35
    Оценка:
    Gaperton wrote:
    >> > А что, невычислимое phi у нас может являеться /доказуемым свойством/?
    >> > Пример в студию
    >
    > R>Свойство программы останавливаться. Его можно доказать протоколом
    > R>работы. Но оно невычислимо.
    >
    > Ок, проблема останова — хороший пример. Есть только один нюанс — Трурль
    > шутит .
    А мне нельзя.. Жаль.
    > Под "свойством" подразумевается логический предикат. В
    > /исчислении предикатов /нас ни в малейшей степени не волнует
    > /вычислимость /этих предикатов. Потому, что нас интересует их
    > доказуемость *в каждом конкретном случае*, а не вообще.

    Я дал формальный ответ на Ваш (категорично сформулированный) вопрос. Я
    согласен, что это как раз пример против предложенного ограничения
    (останавливаемость программ как раз принято доказывать, несмотря на
    неразрешимость). Ваш ответ мне является возражением Трурлю и отказом от
    Вашего вопроса — разве нет?

    > Ограничивать их множеством вычислимых — нахрен не нужно, так как нам не

    > нужно уметь их вычислять. Если мы знаем, что свойство Х *всегда
    > *выполняется на классе объектов Y, то факт наличия этого свойства уже
    > доказан, все
    Я знаю. Я знаю, что всякая уважающая себя (или хотя бы арифметику)
    теория неразрешима или противоречива и это никому не мешает.
    >
    > Мы же не систему поиска вывода пишем (что, кстати, в случае исчисления
    > предикатов сделать невозможно — оно /полуразрешимо/, т.е. там существуют
    > утверждения с бесконечным выводом, как следствие — проблема вывода
    > эквивалентна проблеме останова
    Как я помню, она сложнее, хотя это никому не нужно..
    Posted via RSDN NNTP Server 2.0 beta
    Re[28]: Все еще проще
    От: Gaperton http://gaperton.livejournal.com
    Дата: 05.08.05 18:23
    Оценка:
    Здравствуйте, raskin, Вы писали:

    R>А мне нельзя.. Жаль.

    Кто вас знает, шутите вы или нет. Тэга [joke], [kidding] или (хотя-бы) смайлика я не заметил.

    R>Я дал формальный ответ на Ваш (категорично сформулированный) вопрос

    Спасибо, я прекасно суть вашего ответа. Хочу только в порядке отступления заметить, что вопрос при всем желании нельзя "категорично сформулировать", его в лучшем случае можно "поставить ребром".

    R>Ваш ответ мне является возражением Трурлю и отказом от

    R>Вашего вопроса — разве нет?
    Вопрос я уже задал, получил на него ответ, и отказываться от вопроса уже поздно, не так ли? А возражаю я действительно Трурлю.

    Довольно забавный у нас с вами разговор получается, не находите — мы рассказываем друг другу о том, что мы друг другу говорим. У вас есть идеи — зачем мы это делаем?
    Re[29]: Все еще проще
    От: raskin Россия  
    Дата: 06.08.05 10:43
    Оценка:
    Gaperton wrote:
    > R>А мне нельзя.. Жаль.
    > Кто вас знает, шутите вы или нет. Тэга [joke], [kidding] или (хотя-бы)
    > смайлика я не заметил.
    Ну, формально ответ разве был неверен? Смайлики я просто не привык
    ставить, а указанные средства разметки применяю в опасных случаях.
    > R>Я дал формальный ответ на Ваш (категорично сформулированный) вопрос
    > Спасибо, я прекасно суть вашего ответа. Хочу только в порядке
    > отступления заметить, что вопрос при всем желании нельзя "категорично
    > сформулировать", его в лучшем случае можно "поставить ребром".
    Да, что-то не по-русски у меня получилось.. Я имел в виду, что вопрос
    мне показался подразумевающим несуществование примера такого свойства.
    > R>Ваш ответ мне является возражением Трурлю и отказом от
    > R>Вашего вопроса — разве нет?
    > Вопрос я /уже задал/, получил на него ответ, и отказываться от вопроса
    > уже поздно, не так ли? А возражаю я действительно Трурлю.
    Вопрос мне показался частично риторическим. Соответственно он несёт
    утверждение (как и всякий правильный вопрос...). Ваш первый ответ мне
    нёс в себе утверждение, противоположное тому, которое я увидел
    (возможно, ошибочно) в вопросе. Под отказом от вопроса я имел в виду
    отказ от утверждения, которое подразумевалось (или мне казалось, что
    подразумевается в вопросе).
    > Довольно забавный у нас с вами разговор получается, не находите — мы
    > рассказываем друг другу о том, что мы друг другу говорим. У вас есть
    > идеи — зачем мы это делаем?
    Про себя могу ответить — любимый формализм и иногда проявляющееся
    желание довести его до конца. Кроме того, вот сейчас Вы мне поправили не
    точное формально использование слова категоричность (за что спасибо —
    побудили убедиться, что оно относится всегда к утверждению, не
    подразумевающему возражений, а не к вопросу, который выглядит как
    несущий в себе ответ). Если Вы считаете это бесполезной тратой времени —
    Ваша воля не отвечать, в конце концов, я согласен с Вашим мнением по
    исходному вопросу, и почти согласен со всем последующим.
    Posted via RSDN NNTP Server 2.0 beta
    Re[27]: Все еще проще
    От: Трурль  
    Дата: 08.08.05 05:33
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

    G>Так что не смотря на блестящий пример, предложение Трурля отклоняется.


    Виноват . Как-то упустил, что речь о доказуемых свойствах.
    Но тогда вопрос, как их отделять? Единственно разумным кажется рассматривать только свойства, явно указанные в спецификации класса.
    Re[28]: Все еще проще
    От: Павел Кузнецов  
    Дата: 08.08.05 05:59
    Оценка: +1
    Трурль,

    > Как-то упустил, что речь о доказуемых свойствах. Но тогда вопрос, как их отделять? Единственно разумным кажется рассматривать только свойства, явно указанные в спецификации класса.


    Точно. Именно это и предлагает Барбара Лисков.
    Posted via RSDN NNTP Server 2.0 beta
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.