Re[14]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 11:17
Оценка:
DG>>Между ними можно провести отношение наследования или это совсем разные типы, между которыми ничего общего?
S>Смешно. Ни то ни другое. Наследованием не исчерпываются взаимоотношения между типами.

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

Пример:
Немой человек — это человек, который не может говорить. В данном случае, понятие "немой человек" наследует все свойства, аттрибуты, методы и т.д. понятие человека. Причем понятие "немой человек" может использоваться во всех тех же контекстах, что и понятие "человек".
Замечу, что понятие "немой человек" почти совсем не отличается от понятия "человек" с установленым свойством "голос сорван" в true.

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

S>Можно было бы ввести метаинтерфейс, который содержит все нужные нам мат.операции. Мета — потому, что мы не можем фиксировать тип параметров. Можем только потребовать, чтобы operator + (type, type) возвращал снова type, а не хрен собачий.


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


Почему? Почему мы по целому числу не можем получить натуральное? Из числа с плавающей точкой мы же можем получить целое... И из строки можем получить число...

S>Я бы хотел подчеркнуть, что в такой модели есть два разных объекта "2" — целая двойка и натуральная двойка. У натуральной двойки нет оператора унарного минуса. Поэтому вычитание из 4 2 выглядит примерно так: Integer(Natural(4))+Negation(Integer(Natural(2))).


Что полезного (кроме громоздкости) нам дает такая модель?

Имхо, более удобной является следующая модель: есть один объект "2". При этом этот объект является и натуральным числом, и целым числом, и дробным числом, и даже комплексным числом. Может даже являться строкой "2" или "10", если у нас заспецифицировано, что используется сооветствующая система счисления.


И если мы при делении 7.20 на 3.60 получили объект "2", то этот объект мы можем легко передать кладовщику, чтобы он отгрузил данное (натуральное) кол-во объектов(вещей).
Re[15]: Задачка про Circle/Ellipse: "официальный" ответ.
От: INTP_mihoshi Россия  
Дата: 05.05.04 11:40
Оценка: +1
Здравствуйте, DarkGray, Вы писали:


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


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

В смысле, натуральные числа -наследник действительных.


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

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

Отношение вида sibling, т.е. общие предки/интерфейсы. Еще бывают связи типа "использует" и "включает".


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

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

Ну, в спецификация интерфейсом можно назвать что угодно. Я думал ты имеешь в виду интерфейсы в Com/Corba/Java смысле.

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

Если они не поддерживают стандарт полностью — значит, это не компиляторы языка С++, только и всего. А с вопросом о том, почему стандарт языка не позволяет написать соответствующий ему компилятор — к товарищу Страуструпу.
Re[16]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 12:03
Оценка:
INT>>>Если все методы константны — то вполне могут быть Лисковыми классом и подклассом. Различаются только конструкторы.

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

INT>В смысле, натуральные числа -наследник действительных.

Как в таком случае быть с операцией "отрицание"?


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

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

INT>Ну, в спецификация интерфейсом можно назвать что угодно. Я думал ты имеешь в виду интерфейсы в Com/Corba/Java смысле.


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

An OLE component can implement an interface without implementing all the semantics of every method in the interface, instead returning E_NOTIMPL or S_OK as appropriate. The following table describes those methods that an ActiveX Control container is not required to implement (i.e. the control container can return E_NOTIMPL).

The table below describes optional methods; note that the method must still exist, but can simply return E_NOTIMPL instead of implementing real semantics. Note that any method from a mandatory interface that is not listed below must be considered mandatory and may not return E_NOTIMPL.


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


INT>Если они не поддерживают стандарт полностью — значит, это не компиляторы языка С++, только и всего.


Но ведь ими же пользуются... И пользуются успешно.
Ты ведь не можешь сказать работадателю/клиенту — я не буду писать программу, потому что Ваш/данный компилятор не поддерживает полностью спецификацию C++, а будешь подстраиваться под то, что дали.
Re[17]: Задачка про Circle/Ellipse: "официальный" ответ.
От: INTP_mihoshi Россия  
Дата: 05.05.04 12:23
Оценка:
Здравствуйте, DarkGray, Вы писали:

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

INT>>В смысле, натуральные числа -наследник действительных.

DG>Как в таком случае быть с операцией "отрицание"?

Операция "отрицание" от натурального числа возвращает целое, как и в операция "отрицание" от целого.


INT>>Ну, в спецификация интерфейсом можно назвать что угодно. Я думал ты имеешь в виду интерфейсы в Com/Corba/Java смысле.


DG>И в этом смысле тоже. Так многие Com-овские интерфейсы по спецификации могут быть реализованы частично.


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

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

INT>>Если они не поддерживают стандарт полностью — значит, это не компиляторы языка С++, только и всего.

DG>Но ведь ими же пользуются... И пользуются успешно.
DG>Ты ведь не можешь сказать работадателю/клиенту — я не буду писать программу, потому что Ваш/данный компилятор не поддерживает полностью спецификацию C++, а будешь подстраиваться под то, что дали.

Разумеется, но буду помнить, что то, на чем я пишу является не стандартным С++, а языком "по мотивам".

Извини, если я что-то не в тему говорю — болею. Вообще общая мысль такая — понятия "язык", "интерфейс", "наследование", "класс" и т.д. слишком размыты и многозначны. Тем удивительнее, что их можно использовать в первоначальном "строгом" значении и писать в "строгом" стиле, позволяющем, в частности, формально доказывать свойства программ. Еще больше меня удивляет то, что это можно делать и в С++, причем средств этого языка достаточно для этого практически точь-в-точь, т.е. все, что нужно, и ничего лишнего. Но повторюсь, для "формально корректных" программ нужны возможности С++ целиком, включая множественное наследование, декларацию выкидываемых функцией исключений, частично определенный шаблоны и т.д. Т.е. писать на чем-то, соответствующем стандарту.
Re[15]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.05.04 13:22
Оценка: +1
Здравствуйте, DarkGray, Вы писали:

DG>Для начала хочется увидеть определение отношения "наследование".

DG>В моем понимании "наследование" — это "перенос" признаков, аттрибутов, методов, теорем и т.д. от одного объекта к другому, причем данный перенос может быть, как сужающим, так и расширающим.
Это-то конечно. А в моем понимании негодяй — это человек, который проработал не один год
Просто в ООП традиционно под наследованием понимают операцию, обратную обобщению. А поскольку основой ООП является поведение объектов, то фраза "класс А является обобщением классов A1 и A2" (== "классы A1 и A2 унаследованы от A") может трактоваться только как "объекты классов A1 и A2 обладают некоторым общим поведением, которое унаследовано ими от класса A". И все — мы не можем лишить объекты класса A1 какой-то части поведения объектов класса A. Можем только добавлять.
Используя альтернативные определения наследования можно получать альтернативные результаты.
DG>Почему? Почему мы по целому числу не можем получить натуральное? Из числа с плавающей точкой мы же можем получить целое... И из строки можем получить число...
Ну и какое же натуральное число ты собрался получить из целого числа "-2"? А из строки "бармаглот"?
DG>Что полезного (кроме громоздкости) нам дает такая модель?
А то, что другого варианта корректной эмуляции поведения этих двух классов чисел в рамках ООП я не вижу.
DG>Имхо, более удобной является следующая модель: есть один объект "2". При этом этот объект является и натуральным числом, и целым числом, и дробным числом, и даже комплексным числом. Может даже являться строкой "2" или "10", если у нас заспецифицировано, что используется сооветствующая система счисления.
Ну, смотря для чего эта модель является удобной. Видишь ли, если это целая двойка, то из нее нельзя извлечь квадратный корень — эта операция не определена для целых чисел. Как, впрочем, и для рациональных чисел ты не сможешь статически определить такую операцию. Более того, результат операции 5/2 радикальным образом зависит от того, какие 2 и 5 мы рассматриваем — целые либо рациональные. В твоей более удобной модели нет никакого способа понять, какой из этих результатов будет возвращен! Ведь у тебя ровно одна двойка и одна пятерка! Еще рекомендую подумать над тем, что должен вернуть корень четвертой степени из единицы.
DG>И если мы при делении 7.20 на 3.60 получили объект "2", то этот объект мы можем легко передать кладовщику, чтобы он отгрузил данное (натуральное) кол-во объектов(вещей).
А если не получили? Я не опротестовываю твою модель. Вот только типизация у нее получается сугубо динамическая. Боюсь, к ООП она не сможет иметь никакого отношения.
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.05.04 13:34
Оценка: +1
Здравствуйте, DarkGray, Вы писали:


DG>И в этом смысле тоже. Так многие Com-овские интерфейсы по спецификации могут быть реализованы частично.

Это не больший косяк, чем отказ реализовывать семантику. Я вот сталкивался с тем, что негодяи возвращают S_OK, но при этом не выполняют требований спецификации. Очень, кстати, раздражает.
Фактически, такие вещи — следствие кривого дизайна. Вы посмотрите на объектную модель Екселя! Там с десяток объектов всего. Зато каждый реализует под пару сотен методов. Ага, это они просто не хотели мешать жить тем, кто программирует процедурно. Не хотелось им раскладывать функционал на те самые сто-двести интерфейсов.
Второй вариант — это отсутствие рефакторинга и требования поддержать обратную совместимость. Начиная с аутлука XP, попытка принудительно вызвать доставку почты через MAPI игнорируется. Правильно — это дыра, через которую лазили черви. Увы, то что написано в реестре вырубить топором нельзя. Даже если опубликовать новый интерфейс, то что делать с теми клиентами, которые опираются на старый?
Но это хоть как-то можно понять. А вот опциональные методы в интерфейсах COM — это вообще преступление против теории кристалла. Вместо этого надо было развалить интерфейс на соответствующее количество частей, и не парить мозг разработчикам. Так бы все было просто — допросил объект об интерфейсах — и работай себе. А то для каждого долбаного вызова надо проверять, уж не вернул ли он E_NOTIMPL.
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Gaperton http://gaperton.livejournal.com
Дата: 05.05.04 13:46
Оценка:
Здравствуйте, DarkGray, Вы писали:

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


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

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

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

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

Если операции не имеют деструктивной семантики, то все ништяк. Натуральное число — подкласс целого.

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

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

DG>ps

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

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

Ну вот, самый простой пример. Представь, что у тебя есть написанная и отлаженная подсистема, работающая с абстрактным типом А. Пусть А — это эллипс. Подсистема делает последовательность преобразований
1) Растянуть А по оси ох в два раза.
2) Повернуть А на 90 градусов по часовой стрелке.
3) Растянуть А по оси ох в два раза.
Легко видеть, что это преобразование инвариантно для эллипса, который является кругом. Попробуй написать подкласс А для круга, если перечисленные операции обладают деструктивной семантикой (т. е. они изменяют объект, а не создают новый — что нормально для императивных языков).

Кстати, Лисков — это женщина , и очень умная женщина. Она пока вроде еще жива и преподает в MIT. Живой классик.
Re[16]: Задачка про Circle/Ellipse: "официальный" ответ.
От: INTP_mihoshi Россия  
Дата: 05.05.04 13:47
Оценка:
Здравствуйте, Sinclair, Вы писали:

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



S>Более того, результат операции 5/2 радикальным образом зависит от того, какие 2 и 5 мы рассматриваем — целые либо рациональные. В твоей более удобной модели нет никакого способа понять, какой из этих результатов будет возвращен! Ведь у тебя ровно одна двойка и одна пятерка! Еще рекомендую подумать над тем, что должен вернуть корень четвертой степени из единицы.


Это все глюки sintactic sugar. Целочисленное деление и целое деление — это две большие разницы. И приведение типов — это тоже операция, даже если она не требует упоминания в тексте.

DG>>И если мы при делении 7.20 на 3.60 получили объект "2", то этот объект мы можем легко передать кладовщику, чтобы он отгрузил данное (натуральное) кол-во объектов(вещей).

S>А если не получили? Я не опротестовываю твою модель. Вот только типизация у нее получается сугубо динамическая. Боюсь, к ООП она не сможет иметь никакого отношения.

Типизация у ООП тоже не имеет отношения. Типизация — это свойство контроля правильности и sintactic sugar для операций (чтобы можно было разные / отличать по типам операндов, а не указывать каждый раз).

Кстати, чем динамическая типизация отличается от статической кроме того, что в ней иногда можно опускать упоминания операции приведения типа?
Re[16]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 13:50
Оценка:
DG>>Для начала хочется увидеть определение отношения "наследование".
DG>>В моем понимании "наследование" — это "перенос" признаков, аттрибутов, методов, теорем и т.д. от одного объекта к другому, причем данный перенос может быть, как сужающим, так и расширающим.
S>Просто в ООП традиционно под наследованием понимают операцию, обратную обобщению. А поскольку основой ООП является поведение объектов, то фраза "класс А является обобщением классов A1 и A2" (== "классы A1 и A2 унаследованы от A") может трактоваться только как "объекты классов A1 и A2 обладают некоторым общим поведением, которое унаследовано ими от класса A".

согласен.

S> И все — мы не можем лишить объекты класса A1 какой-то части поведения объектов класса A. Можем только добавлять.


Не согласен.
Обобщение — есть обобщение. Где сказано, что обобщение должно давать пересечение (а не сумму) операций, доступных для объектов A1 и A2.

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

S>Используя альтернативные определения наследования можно получать альтернативные результаты.

DG>>Почему? Почему мы по целому числу не можем получить натуральное? Из числа с плавающей точкой мы же можем получить целое... И из строки можем получить число...
S>Ну и какое же натуральное число ты собрался получить из целого числа "-2"?

Либо 0, либо ошибку, либо 2, взависимости от контекста.

S> А из строки "бармаглот"?


либо ошибку, либо 0, либо некое число, если это слово на каком-то языке обозначает число.

DG>>Что полезного (кроме громоздкости) нам дает такая модель?

S>А то, что другого варианта корректной эмуляции поведения этих двух классов чисел в рамках ООП я не вижу.

Человек оперируется окружающим миром в рамках ООП или нет?
Если в рамках ООП, то почему человек может, а машина — нет?


DG>>Имхо, более удобной является следующая модель: есть один объект "2". При этом этот объект является и натуральным числом, и целым числом, и дробным числом, и даже комплексным числом. Может даже являться строкой "2" или "10", если у нас заспецифицировано, что используется сооветствующая система счисления.

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

Где не опредена? В языке C?

Кто сказал, что результат операции должен принадлежать тому же типу, что и операнды?

S> Как, впрочем, и для рациональных чисел ты не сможешь статически определить такую операцию.

S> Более того, результат операции 5/2 радикальным образом зависит от того, какие 2 и 5 мы рассматриваем — целые либо рациональные. В твоей более удобной модели нет никакого способа понять, какой из этих результатов будет возвращен!
S> Ведь у тебя ровно одна двойка и одна пятерка!

Возвращается всегда объект "2.5", но если мы работаем в поле целых чисел, то данных объект преобразуется к 2.

S> Еще рекомендую подумать над тем, что должен вернуть корень четвертой степени из единицы.


Возвращается множество {-1; 1; i}, если мы работаем в поле натуральных чисел, то результат будет 1, если действительных, то {-1; 1}, если в поле комплексных, то все множество.

DG>>И если мы при делении 7.20 на 3.60 получили объект "2", то этот объект мы можем легко передать кладовщику, чтобы он отгрузил данное (натуральное) кол-во объектов(вещей).

S>А если не получили? Я не опротестовываю твою модель. Вот только типизация у нее получается сугубо динамическая. Боюсь, к ООП она не сможет иметь никакого отношения.

Кто сказал, что ООП должна быть статической?
Статическая типизация нам только дает только одно преимущество, по сравнению с динамической. Основным преимуществом статической типизации является то, что мы заранее (на этапе компиляции) можем проверить правильность выражений.
Всё. Больше преимуществ нет.
Re[14]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 13:59
Оценка:
DG>>Т.е. получается, что мы должны отдельно завести тип целое число, определить для него операции, потом отдельно завести тип натуральное число опять определив все операции?
DG>>Потом также отдельно завести типы [0..10), [-4..1000], [0..255], [0..65535] и т.д.?
G>Да. Именно так. В противном случае наследование будет использовано не по назначению.

Приведи, пожалуйста, твое определение понятие "наследование".

DG>>ps

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

G>Найди в гугле материал по "Liskov Substitution Principle", там на примерах объясняется, чем в реальной жизни чревато нарушение этого принципа. А чревато оно настолько, что надо вырывать руки нах программерам, которые им пренебрегают.


не нашел там примеров из реальной жизни

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

G>1) Растянуть А по оси ох в два раза.
G>2) Повернуть А на 90 градусов по часовой стрелке.
G>3) Растянуть А по оси ох в два раза.
G>Легко видеть, что это преобразование инвариантно для эллипса, который является кругом. Попробуй написать подкласс А для круга, если перечисленные операции обладают деструктивной семантикой (т. е. они изменяют объект, а не создают новый — что нормально для императивных языков).

И в чем в данном случае проблема?

тип объекта будет меняться следующим образом.
1) круг -> эллипс
2) эллипс -> эллипс
3) эллипс -> круг
Re[15]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Gaperton http://gaperton.livejournal.com
Дата: 05.05.04 14:50
Оценка:
Здравствуйте, DarkGray, Вы писали:

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

G>>1) Растянуть А по оси ох в два раза.
G>>2) Повернуть А на 90 градусов по часовой стрелке.
G>>3) Растянуть А по оси ох в два раза.
G>>Легко видеть, что это преобразование инвариантно для эллипса, который является кругом. Попробуй написать подкласс А для круга, если перечисленные операции обладают деструктивной семантикой (т. е. они изменяют объект, а не создают новый — что нормально для императивных языков).

DG>И в чем в данном случае проблема?


DG>тип объекта будет меняться следующим образом.

DG>1) круг -> эллипс
DG>2) эллипс -> эллипс
DG>3) эллипс -> круг

Проблема в том, что деструктивные операции замкнуты, т. е. не могут изменить класс объекта. Ну не может в ООП меняться тип во время жизни объекта. И мне крайне любопытно, как будут выглядеть реализации этой пары методов. Тот код, который ты присылал, совершенно не решает проблемы. Учти, что класс А не абстрактный и не интерфейс — это самый полноценный эллипс.
Re[16]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 15:15
Оценка:
G>Проблема в том, что деструктивные операции замкнуты, т. е. не могут изменить класс объекта.

G> Ну не может в ООП меняться тип во время жизни объекта.


кто сказал, что в ООП не может меняться тип объекта?

G> И мне крайне любопытно, как будут выглядеть реализации этой пары методов. Тот код, который ты присылал, совершенно не решает проблемы. Учти, что класс А не абстрактный и не интерфейс — это самый полноценный эллипс.


class Figure
{
  object GetService(Type type)
  {
    if (type == typeof(Circle) && IsCircle)
      return new Circle(this);
    if (type == typeof(Ellipse) && IsEllipse)
      return new Ellipse(this);
    throw new Exception ("Данный тип не поддерживается данной фигурой"); 
  }
}


Вот и, например, код для приведенного тобой алгоритма:
Figure f;
((Ellipse)f.GetService(typeof(Ellipse))).Resize(2);
((Ellipse)f.GetService(typeof(Ellipse))).Rotate(Pi/2);
((Ellipse)f.GetService(typeof(Ellipse))).Resize(2);


Какое из ООП-правил нарушается для данного кода?
Re[17]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.05.04 15:31
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>Не согласен.

DG>Обобщение — есть обобщение. Где сказано, что обобщение должно давать пересечение (а не сумму) операций, доступных для объектов A1 и A2.
DG>Пример обобщения:
DG>Над фигурой возможны следующие операции: передвинуть, повернуть, изменить размер.
DG>Но для фигур "точки", "окружности", "всей плоскости" часть из этих операций бессмыслена.
В таком случае т ы получаешь класс тигра, который ест все ((с) А.А.Милн). Забавная штука, но практической ценности не имеющая. Это означает отсутствие какой бы то ни было классификации, поскольку любой объект потенциально обладает поведением любого другого объекта, стало быть по его типу нельзя делать никаких выводов о его поведении. Примером такой системы может считаться JavaScript. Не имею ничего против подобных моделей, но лично предпочитаю иметь в запасе несколько более декларативно выразительные средства разработки.
S>>Используя альтернативные определения наследования можно получать альтернативные результаты.
S>>Ну и какое же натуральное число ты собрался получить из целого числа "-2"?
DG>Либо 0, либо ошибку, либо 2, взависимости от контекста.
Очень интересно. А как ты определишь "контекст"? Да еще так, чтобы он был достаточно очевиден?
S>> А из строки "бармаглот"?
DG>либо ошибку, либо 0, либо некое число, если это слово на каком-то языке обозначает число.
Увы, не означает.
DG>>>Что полезного (кроме громоздкости) нам дает такая модель?
S>>А то, что другого варианта корректной эмуляции поведения этих двух классов чисел в рамках ООП я не вижу.

DG>Человек оперируется окружающим миром в рамках ООП или нет?

Чего?
DG>Если в рамках ООП, то почему человек может, а машина — нет?
Чего?

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

DG>Где не опредена? В языке C?
В математике, друг мой, в математике. Которая доказала свою полезность массой замечательных результатов, наблюдаемых на каждом шагу.
DG>Кто сказал, что результат операции должен принадлежать тому же типу, что и операнды?
Никто не сказал. Просто в математике операции, про которые мы говорим, традиционно определяются именно так. Никто не мешает сделать незамкнутую операцию сложения двух элементов множества.
DG>Возвращается всегда объект "2.5", но если мы работаем в поле целых чисел, то данных объект преобразуется к 2.
Очень здорово. А это комплексная 2.5 или вещественная? Или это кватернион? А может, это комплексный тензор ранга 1?
DG>Возвращается множество {-1; 1; i}, если мы работаем в поле натуральных чисел, то результат будет 1, если действительных, то {-1; 1}, если в поле комплексных, то все множество.
Ну, во первых должно все-таки вернуться множество {-1; 1; i;-i}. Во вторых, это выглядит несколько искусственно, согласись. Для того, чтобы банально определить, какое натуральное число дает 16, будучи умноженным само на себя четырежды, мы вынуждены выполнять комплексные операции с множествами, а потом выбирать те из результатов, которые лежат в том множестве, с которым мы работаем. Имхо, это неоправданное усложнение простой модели. По крайней мере, в математике по этому пути не пошли.
DG>Кто сказал, что ООП должна быть статической?
Да никто не сказал. Пожалуйста — вот тебе JavaScript.
DG>Статическая типизация нам только дает только одно преимущество, по сравнению с динамической. Основным преимуществом статической типизации является то, что мы заранее (на этапе компиляции) можем проверить правильность выражений.
DG>Всё. Больше преимуществ нет.
Ну как тебе сказать. Вообще говоря, помимо этого можно эффективно выполнять некоторые оптимизации.
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.05.04 15:31
Оценка:
Здравствуйте, INTP_mihoshi, Вы писали:
S>>Более того, результат операции 5/2 радикальным образом зависит от того, какие 2 и 5 мы рассматриваем — целые либо рациональные. В твоей более удобной модели нет никакого способа понять, какой из этих результатов будет возвращен! Ведь у тебя ровно одна двойка и одна пятерка! Еще рекомендую подумать над тем, что должен вернуть корень четвертой степени из единицы.
INT>Это все глюки sintactic sugar. Целочисленное деление и целое деление — это две большие разницы. И приведение типов — это тоже операция, даже если она не требует упоминания в тексте.
Не понял. Про какой такой сахар ты упомянул? Про то, что у нас есть возможность неявно преобразовывать 2 к 2.0? Ну так это и есть то, о чем я говорю — целая двойка — это совсем другой объект, чем 2.0.
INT>Типизация у ООП тоже не имеет отношения. Типизация — это свойство контроля правильности и sintactic sugar для операций (чтобы можно было разные / отличать по типам операндов, а не указывать каждый раз).
Ну, я не уверен в правильности своих определений, но я имел в виду не перегрузку операций по типам операндов, а то, что ADT однозначно определяет набор применимых к нему операций. Перегрузка — совершенно необязательный атрибут. Можешь считать, что 2.0 и 2 отличаются ровно тем, что к первому применимо DivideFloats(,), а ко второму — нет.
INT>Кстати, чем динамическая типизация отличается от статической кроме того, что в ней иногда можно опускать упоминания операции приведения типа?
Ну, вообще-то в статической типизации тоже можно опускать операции приведения типа. Основное отличие — в том, что тип выражения нельзя определить до его вычисления. В предлагаемой модели результат конкатенации строк "1" и "0" ведет себя как число, а результат конкатенации строк "де" и "дуля" — нет.
Хуже того, в предлагаемой модели вообше как-то странно говорить о типе, т.к. он не определяет никаких свойств объекта. Потому как к нему потенциально применима любая операция, а стало быть все объекты равноправны. Это уже нестрогая типизация.
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 15:59
Оценка:
DG>>Не согласен.
DG>>Обобщение — есть обобщение. Где сказано, что обобщение должно давать пересечение (а не сумму) операций, доступных для объектов A1 и A2.
DG>>Пример обобщения:
DG>>Над фигурой возможны следующие операции: передвинуть, повернуть, изменить размер.
DG>>Но для фигур "точки", "окружности", "всей плоскости" часть из этих операций бессмыслена.
S>В таком случае т ы получаешь класс тигра, который ест все ((с) А.А.Милн).

Почему всё? Я же четко определил, что для фигуры определены 3 операции. А дальше идет нечеткая логика:
для большинства (но не для всех) фигур — эти операции выполняются корректно.

S> Забавная штука, но практической ценности не имеющая. Это означает отсутствие какой бы то ни было классификации, поскольку любой объект потенциально обладает поведением любого другого объекта, стало быть по его типу нельзя делать никаких выводов о его поведении. Примером такой системы может считаться JavaScript. Не имею ничего против подобных моделей, но лично предпочитаю иметь в запасе несколько более декларативно выразительные средства разработки.


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

S>>>Используя альтернативные определения наследования можно получать альтернативные результаты.

S>>>Ну и какое же натуральное число ты собрался получить из целого числа "-2"?
DG>>Либо 0, либо ошибку, либо 2, взависимости от контекста.
S>Очень интересно. А как ты определишь "контекст"? Да еще так, чтобы он был достаточно очевиден?

например, по тому типу, которому присваивается результат.
или, например, по настройкам в реестре или еще где-то.
или банально:
void Func()
{
  context<int>
  {
    Out(2/5);
  }
}


DG>>>>Что полезного (кроме громоздкости) нам дает такая модель?

S>>>А то, что другого варианта корректной эмуляции поведения этих двух классов чисел в рамках ООП я не вижу.

Что значит корректной? и что значит рамки ООП?


DG>>Кто сказал, что результат операции должен принадлежать тому же типу, что и операнды?

S>Никто не сказал. Просто в математике операции, про которые мы говорим, традиционно определяются именно так. Никто не мешает сделать незамкнутую операцию сложения двух элементов множества.
DG>>Возвращается всегда объект "2.5", но если мы работаем в поле целых чисел, то данных объект преобразуется к 2.
S>Очень здорово. А это комплексная 2.5 или вещественная? Или это кватернион? А может, это комплексный тензор ранга 1?

Если мы "знаем" про тензоры и кватернионы, то это и второе, и третье. и четвертое.

DG>>Возвращается множество {-1; 1; i}, если мы работаем в поле натуральных чисел, то результат будет 1, если действительных, то {-1; 1}, если в поле комплексных, то все множество.

S>Ну, во первых должно все-таки вернуться множество {-1; 1; i;-i}. Во вторых, это выглядит несколько искусственно, согласись. Для того, чтобы банально определить, какое натуральное число дает 16, будучи умноженным само на себя четырежды, мы вынуждены выполнять комплексные операции с множествами, а потом выбирать те из результатов, которые лежат в том множестве, с которым мы работаем. Имхо, это неоправданное усложнение простой модели. По крайней мере, в математике по этому пути не пошли.

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

class Number
{
   SqrtResult Sqrt()
   {
     return new SqrtResult(this);
   }
}
class SqrtResult
{
  Number source;
  operator Number()
  {
    return SimpleSqrt(source);
  }
  operator Complex()
  {
    return ComplexSqrt(source);
  }
}



DG>>Кто сказал, что ООП должна быть статической?

S>Да никто не сказал. Пожалуйста — вот тебе JavaScript.

Тогда уж Smalltalk, JavaScript — все-таки скрипт(интерпетатор), а не полноценный язык.

DG>>Статическая типизация нам только дает только одно преимущество, по сравнению с динамической. Основным преимуществом статической типизации является то, что мы заранее (на этапе компиляции) можем проверить правильность выражений.

DG>>Всё. Больше преимуществ нет.
S>Ну как тебе сказать. Вообще говоря, помимо этого можно эффективно выполнять некоторые оптимизации.

Оптимизации можно делать и при динамической типизации, например, используя тот же lazy-подход.
Re[17]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.05.04 16:20
Оценка:
Здравствуйте, DarkGray, Вы писали:
DG>кто сказал, что в ООП не может меняться тип объекта?
DG>
DG>class Figure
DG>{
DG>  object GetService(Type type)
DG>  {
DG>    if (type == typeof(Circle) && IsCircle)
DG>      return new Circle(this);
DG>    if (type == typeof(Ellipse) && IsEllipse)
DG>      return new Ellipse(this);
DG>    throw new Exception ("Данный тип не поддерживается данной фигурой"); 
DG>  }
DG>}
DG>

Ну что за подтасовки! Это та самая эмуляция поведения неоюбъеектных сущностей при помощи ООП. При помощи (конечно же!) создания нового объекта. Ты же только что критиковал меня за введение двух разных двоек. Ай-яй-яй, как нехорошо .
Увы, то, что ты потерял, называется Identity.
Вот этот код:
Figure f;
((Ellipse)f.GetService(typeof(Ellipse))).Resize(2);
((Ellipse)f.GetService(typeof(Ellipse))).Rotate(Pi/2);
((Ellipse)f.GetService(typeof(Ellipse))).Resize(2);

на самом деле действительно приводит к тому, что иходный f совпадает с конечным. Потому, что все операции применяются к трем совершенно разным временным объектам
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 16:55
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

DG>>кто сказал, что в ООП не может меняться тип объекта?
DG>>
DG>>class Figure
DG>>{
DG>>  object GetService(Type type)
DG>>  {
DG>>    if (type == typeof(Circle) && IsCircle)
DG>>      return new Circle(this);
DG>>    if (type == typeof(Ellipse) && IsEllipse)
DG>>      return new Ellipse(this);
DG>>    throw new Exception ("Данный тип не поддерживается данной фигурой"); 
DG>>  }
DG>>}
DG>>

S>Ну что за подтасовки! Это та самая эмуляция поведения неоюбъеектных сущностей при помощи ООП. При помощи (конечно же!) создания нового объекта. Ты же только что критиковал меня за введение двух разных двоек. Ай-яй-яй, как нехорошо .

То что создается новый объект — это деталь реализации.

Могу функцию GetService объявить так (так называемый "жирный интерфейс"):
class Figure:
  Circle,
  Ellipse
{
  object GetService(Type type)
  {
    if (type == typeof(Circle) && IsCircle)
      return this;
    if (type == typeof(Ellipse) && IsEllipse)
      return this;
    throw new Exception ("Данный тип не поддерживается данной фигурой"); 
  }
}


Могу объявить вот так (подход под названием "подключение реализаций"):
class Figure
{
  public Figure()
  {
    this.circle = new Circle(this);
    this.ellipse = new Ellipse(this);
  }
  Circle circle;
  Ellipse ellipse;

  object GetService(Type type)
  {
    if (type == typeof(Circle) && IsCircle)
      return circle;
    if (type == typeof(Ellipse) && IsEllipse)
      return ellipse;
    throw new Exception ("Данный тип не поддерживается данной фигурой"); 
  }
}


S>Увы, то, что ты потерял, называется Identity.


С чего ты это взял?
У классов Circle и Ellipse перекрытая операция ==, которая сравнивает через фигуру.

ps
Агрегирование в Com-е построено именно по такому принципу. Но аггрегирование — это и есть наследование.

S>Вот этот код:

S>
S>Figure f;
S>((Ellipse)f.GetService(typeof(Ellipse))).Resize(2);
S>((Ellipse)f.GetService(typeof(Ellipse))).Rotate(Pi/2);
S>((Ellipse)f.GetService(typeof(Ellipse))).Resize(2);
S>


S>на самом деле действительно приводит к тому, что иходный f совпадает с конечным. Потому, что все операции применяются к трем совершенно разным временным объектам


Для внешнего кода — это один и тот же объект, потому что он выглядит как один объект.
Re[17]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Gaperton http://gaperton.livejournal.com
Дата: 05.05.04 17:09
Оценка:
Здравствуйте, DarkGray, Вы писали:


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


G>> Ну не может в ООП меняться тип во время жизни объекта.


DG>кто сказал, что в ООП не может меняться тип объекта?


G>> И мне крайне любопытно, как будут выглядеть реализации этой пары методов. Тот код, который ты присылал, совершенно не решает проблемы. Учти, что класс А не абстрактный и не интерфейс — это самый полноценный эллипс.


DG>
DG>class Figure
DG>{
DG>  object GetService(Type type)
DG>  {
DG>    if (type == typeof(Circle) && IsCircle)
DG>      return new Circle(this);
DG>    if (type == typeof(Ellipse) && IsEllipse)
DG>      return new Ellipse(this);
DG>    throw new Exception ("Данный тип не поддерживается данной фигурой"); 
DG>  }
DG>}
DG>


DG>Вот и, например, код для приведенного тобой алгоритма:

DG>
DG>Figure f;
DG>((Ellipse)f.GetService(typeof(Ellipse))).Resize(2);
DG>((Ellipse)f.GetService(typeof(Ellipse))).Rotate(Pi/2);
DG>((Ellipse)f.GetService(typeof(Ellipse))).Resize(2);
DG>


DG>Какое из ООП-правил нарушается для данного кода?

1) Этот код просто-напросто не работает. У тебя нигде не сохраняется промежуточный результат. У тебя только что созданный объект удаляется после каждой операции. Нехорошо. Нерабочий код за пример не канает.
2) В реальном мире ты не всегда можешь менять реализацию компонента. Я же сказал — он уже написан и отлажен.
И написан он вот как:
void Component::DoSomething( Ellipse i_ellipse )
{
   i_ellipse.ResizeOX( 2 );
   i_ellipse.Rotate( Pi / 2 );
   i_ellipse.ResizeOX( 2 );

   DoSomethingElse( i_ellipse );
}

Компонент к тому-же большой и сложный, и отрефакторить нет возможности. Очень реалистичная ситуация.
ВОТ ТЕПЕРЬ напиши такой подкласс Ellipse, который будет Circle. Об этом были примеры Лисков.
Re[19]: Задачка про Circle/Ellipse: "официальный" ответ.
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.05.04 17:11
Оценка: +1
Здравствуйте, DarkGray, Вы писали:

DG>Почему всё? Я же четко определил, что для фигуры определены 3 операции.

Мало ли что ты определил. А для строк определены еще пять. Поскольку у тебя неизвестно, означает ли строка "треугольник" фигуру, придется всем реализовывать по восемь. Или ты заплатки приделаешь? Типа вот тут была строгая типизация, а теперь не совсем?
DG>А дальше идет нечеткая логика:
DG>для большинства (но не для всех) фигур — эти операции выполняются корректно.
Угу. А почему бы вероятность корректного выполнения не ввести? Чтобы уж до конца по нечеткой логике пройти? Иначе ценность этого утверждения равна нулю. Я бы, как работодатель, на утверждение "моя программа в некоторых (но не во всех) случаях делает что-то осмысленное", сказал бы "ну, в некоторых (не во всех) случаях я заплачу" .
DG>Удобнее смешивать статическую и динамическую типизацию, и на практике, динамическая типизация используется очень часто.
DG>Взять тот же графический редактор. Без динамической типизации редактор просто не написать.
Честно говоря, ни разу не пробовал писать объектно-ориентированный графический редактор. Почему-то мне не кажется, что я не напишу его без динамической типизации.

DG>например, по тому типу, которому присваивается результат.

DG>или, например, по настройкам в реестре или еще где-то.
Я рад. Отладка такой программы будет представлять собой сущее удовольствие. Особенно меня интересует процесс введения новых контекстов и обеспечение их миграции в распределенной среде (ну или хотя бы при инсталляции )
DG>или банально:
DG>
DG>void Func()
DG>{
DG>  context<int>
DG>  {
DG>    Out(2/5);
DG>  }
DG>}
DG>

Ну вот примерно это я себе и представлял, когда ты говорил о контексте. А теперь скажи мне, чем это вдруг стало лучше старого доброго
void Func()
{
Out(int(2.0)/int(5.0);
}
? (Я, конечно, имею в виду совершенно обратный случай)
DG>>>>>Что полезного (кроме громоздкости) нам дает такая модель?
S>>>>А то, что другого варианта корректной эмуляции поведения этих двух классов чисел в рамках ООП я не вижу.

DG>Что значит корректной?

А той, что привычные нам математические операции имеют привычную семантику. И умножение вектора на скаляр дает всегда вектор, а не только утром в понедельник. И некоторым комплексным числам соответствуют целые, а некоторым — нет. Поэтому преобразование из целых в комплексные мы можем себе позволить сделать неявно, а в обратную сторону — явно. А еще лучше — потребовать ловить исключение InvalidTypeCast на случай отсутствия соответствия каким-то явным образом, хоть
int Int(Complex c) 
{
  InvalidTypeCastYields<0>
  {
      return (int)c;
  }
}

хоть
int Int(Complex c) 
{
  try
       return (int)c;
    catch(InvalidTypeCast)
      return 0;
}

DG>и что значит рамки ООП?
А это как раз и значит, что поведение объектов детерминировано.
DG>Если мы "знаем" про тензоры и кватернионы, то это и второе, и третье. и четвертое.
Зашибись. То есть от того, что я взял и в своем углу проекта кватернион заимплементил, ты должен там у себя весь код прошерстить на предмет потери семантики? Очень здорово.
DG>на практике используют lazy-подход. Такой подход часто применяется при работе с матрицами.
DG>При таком подходе операции реально выполняются только когда действительно нужен результат.
А, ну это — по-нашему. То есть мы откладываем валидацию до тех приятных времен, когда она уже ничем не сможет нам помочь Я представляю счастье того, кто обнаружит неприводимость строки "дапошливывсе" к дате експирации кредитной карточки в webcommerce проекте. Его ждет незабываемый поиск возможного источника этого чуда, потому что отрепортят ему только локейшн чтения, а никак не записи.

DG>Тогда уж Smalltalk, JavaScript — все-таки скрипт(интерпетатор), а не полноценный язык.

Э, брат, не пойдет. Смолток — динамически, но строго типизированный язык. А ты пытаешься тут изобрести язык, где пока Ева не взяла то, что ей дали, в рот, оно могло быть вовсе и не яблоком.
DG>Оптимизации можно делать и при динамической типизации, например, используя тот же lazy-подход.
Ага. Только совсем другие. Я тебе не открою тайну, если скажу, что lazy-подход возможен и в статике?
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Задачка про Circle/Ellipse: "официальный" ответ.
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.05.04 17:24
Оценка:
DG>>Какое из ООП-правил нарушается для данного кода?
G>1) Этот код просто-напросто не работает. У тебя нигде не сохраняется промежуточный результат. У тебя только что созданный объект удаляется после каждой операции. Нехорошо. Нерабочий код за пример не канает.

Результат сохраняется в самой фигуре.

G>2) В реальном мире ты не всегда можешь менять реализацию компонента. Я же сказал — он уже написан и отлажен.

G>И написан он вот как:
G>
G>void Component::DoSomething( Ellipse i_ellipse )
G>{
G>   i_ellipse.ResizeOX( 2 );
G>   i_ellipse.Rotate( Pi / 2 );
G>   i_ellipse.ResizeOX( 2 );

G>   DoSomethingElse( i_ellipse );
G>}
G>

G>Компонент к тому-же большой и сложный, и отрефакторить нет возможности. Очень реалистичная ситуация.
G>ВОТ ТЕПЕРЬ напиши такой подкласс Ellipse, который будет Circle. Об этом были примеры Лисков.

например, вот так:
class Figure
{
  Hashtable storage = new Hashtable();

  object GetService(Type type)
  {
    if (type == typeof(Circle) && IsCircle)
      return new Circle(this);
    if (type == typeof(Ellipse) && IsEllipse)
      return new Ellipse(this);
    throw new Exception ("Данный тип не поддерживается данной фигурой"); 
  }
  operator Ellipse()
  {
    return (Ellipse)GetService(typeof(Ellipse));
  }
  operator Circle()
  {
    return (Circle)GetService(typeof(Circle));
  }
}
class Ellipse
{
  public Ellipse(Figure figure){this.figure = figure;}
  Figure figure;
  public double Angle {get {return (double)figure.storage["Angle"];} set {figure.storage["Angle"] = value;}
  public double Width {get {return (double)figure.storage["Width"];} set {figure.storage["Width"] = value;}
  public void ResizeOX(double k)
  {
    Width = Width * k;
  }
  public void Rotate(double angle)
  {
    Angle = Angle + angle;
  }
}

//вызов уже написанного компонента:
void Main()
{
  Figure f = new Figure();
  Component c = new Component();
  c.DoSomeThing(f);
}
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.