Re: True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 16.01.05 15:27
Оценка: 11 (3) +9
Здравствуйте, Poudy, Вы писали:

P>В свою очередь для ОО-библиотек есть похожие несуразности, которые я отношу к звеньям той же цепи:


P>1. Библиотека не последовательна в функциональности классов. Пример: в System.Windows.Forms.MenuItem нет Tag, а в std::string нет toUpper/toLower.


Ничего странного в этом нет. Функциональности на все-про-все не напасешься. Это следует из принципов устройства нашей Вселенной — нам не дано знать будущее. Другое дело, как в случае необходимости расширить функциональность. Обычно начинающие лихо делают новый класс-потомок и добавляют туда требуемые функции. то есть, делается string_ex и используется везде, где только можно (сам так делал и очень быстро прекратил). Это очень плохая практика, приводящяя к полному бардаку и появлению нелепых конструкций, типа
((string_ex*)(&str))->toLower();

Наиболее правильным было бы сделать просто функцию toLower(std::string& s). Наследование нелепо еще и потому, что в данных случаях приводит к искусственным иерарархиям классов. Программисты из одного отдела сделали string_ex и "законодательно" объявили о замораживании интерфейса. Программистам из другого отдела понадобилась еще какая-то функция, вот у нас уже появилась string_ex2. И так далее.
В случае использования простых функций не требуется никаких левых иерархий и никаких дополнительных имен классов (что IMO даже более важно, чем наличие левых иерерхий само по себе). Применительно к std::string нет никакой разницы между записями str.toLower() и toLower(str). Для данного случая, расуждения о важности идеи посылки сообщений — не более чем демагогоия.

Можно возразить, что например, требуется сделать синхронизированную, thread safe строку. Следовательно, надо в классе хранить mutex. Но ведь это не добавление функциональности. Это глобальное изменение функциональности! И наследование здесь тем более неуместно. Здесь нужна инкапсуляция с аккуратным переопределением всех методов. Много писать? Да, много. Но все другие варианты — еще хуже. Заметьте, что при этом та же самая шаблонная toLower() проболжает без каких-либо изменений функционировать для обейх вариантов string. На мой взгляд, корень проблемы находится в нечетком понимании (а часто — в полном непонимании) принципов декомпозиции функциональности.

P>2. Иерархия классов странная (больше относится к custom библиотекам). Каждое десятый пост в форуме Проектирование о том, как спроектировать очередную странную иерархию, где Readonly, Admin, Web и прочая функциональность сильно переплетены, и автор непременно хочет заморозить всё это в статичном виде.


Вот в том-то и недостаток идеи наследования. После того, как иерархия создана, нет ни малейшей возможности проявить хоть какую-то гибкость. Взять ту же MFC. Есть класс CDC, у которого есть потомки, типа CClientDC и др. В нем так же есть функция PolyPolygon, которую я хочу заменить своей (более правильной, быстрой, причина на важна). Так каким образом не трогая исходников, я могу включить свой класс (с этой переопределенной функцией) в иерархию между CDC и CClientDC? Никаким! Таким образом, библиотека любой сложности, основанная на принципах иерерхий классов, является абсолютно черным ящиком и использовать ее можно лишь одним единственным способом: "щелкни кобылу в нос — она махнет хвостом".

P>Обсудить хочу следующий принцип для разработки ОО-библиотек:

P>

P>Каждый проблемный домен должен содержать свой центральный класс, содержащий наиболее полную (а не наиболее непротиворечивую) для данного домена функциональность.


Понятие "наиболее полная функциональность" — это абсурд в силу принципов организации нашей Вселенной... Так, я это уже говорил...

Нужно заботиться не о "наиболее полной" функциональности, а прежде всего — о возможности расширения функциональности. А использование иерерхий классов в корне противоречит идее о возможностях расширения.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 15:44
Оценка: 21 (1) +1 :))) :)))
Здравствуйте, Gaperton, Вы писали:

P>>Я сильно не прав?

G>Сам думай
Я-то думаю... да думаю ни кто тут меня не понимааает .
А ваще это как закономерность уже. Стоит написать "такая-то вещь кажется неудобной", как нарвешься на "Ах, ты не любишь шаблоны??!! Ты не любишь C++??????!!! Да что ты понимаешь! Ты быть может еще и UML не любишь? С проектированием не дружишь? Ты что, имеешь в виду, что .net лучше всех? Зачем ты написал, что любишь microsoft?! Отвечай, зачем ты зареал милиционера, убийца!!!!!"

P.S.: всё исключительно на правах шутки.
Re[3]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 17.01.05 17:42
Оценка: 47 (6) :)
Здравствуйте, Poudy, Вы писали:

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


P>Выходит, по твоему TRUE OOP — это язык без статического наследования? Или Python?


Я бы сказал, что вообще идея наследования объектов — порочна в самой своей сущности. Идея объектов, как черных ящиков, передача сообщений, интерфейсы, полиморфизм — это все правильно, ибо достаточно хорошо отражает реальные задачи и реальный мир. Это и есть ООП. Идея же наследования свойств (и построения статических иерархий) — порочна, поскольку не имеет ничего общего с реальной жизнью. Наследование лишь приводит к жесткой связности (tight coupling), в результате чего, вся библиотека сама по себе становится одним большим черным ящиком. Мое утверждение таково: полиморфизим — хорошо, наследование — плохо. Что, разве нельзя реализовать полиморфизм (в том числе и динамический) без наследования? Вполне можно, технически для этого нет никаких препятствий: http://www.rsdn.ru/Forum/Message.aspx?mid=975011&only=1
Автор: c-smile
Дата: 05.01.05


Да, как справедливо заметил AndrewVK, таким способом нельзя реализовать некоторые вещи.
Автор: AndrewVK
Дата: 06.01.05
Но ведь, если вдуматься, эти "вещи" как раз и являются следствием "зависания" на парадигме наследования. И причем, не просто "зависания", а использования идеи наследования неестественным образом — преобразованием от базового класса к производному (upcast или downcast — я их все время путаю, поскольку до сих пор не знаю, куда растет дерево наследования — вверх или вниз ). На мой взгляд, как только возникает необходимость в таком преобразовании, значит что-то здесь не так, и это является серьезной уликой попыток решать неуместные задачи.

Иными словами, я бы однозначно исключил из понятия ООП понятие наследования, как полностью себя дискредитировавшее. И чем мне не нравятся ни Java, ни C# — так это тем, что порочная в своей сущности идея наследования в этих языках возведена в ранг неоспоримого догмата и единственного "правильного" способа написания программы. В C++ — это не более чем замшелая традиция, в Java и C# — центральная идея.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: True OOP
От: Mika Soukhov Stock#
Дата: 16.01.05 18:20
Оценка: :))) :))) :)
Здравствуйте, Poudy, Вы писали:

P>....И все деньги не заработаешь.


Часть придется украсть
Re[3]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 17.01.05 16:30
Оценка: 1 (1) +3
Здравствуйте, Poudy, Вы писали:

P>Мне кажется просто, что STL и прочее писалось в бородатые года и как только появлялась необходимость в расширяемости народ качало из шаблонов в процедуры и назад, вместо использования стратегий и других паттернов. А почему? А потому что нет сборки мусора и вообще проблема с объектами (то он в куче, то в стеке).


Так. Пожалуйста, официант, мухи — отдельно, котлеты — отдельно.

P>Я не спорю, что для C++ всё это верно. Я говорю, что это особенности реализации, а не принцип.


Это именно принцип. Не знаю, сумею ли донести свою мысль, она у меня самого живет лишь на уровне интуиции. Эта мысль очень созвучна с принципом бритвы Оккама, "не плодите сущностей сверх необходимости". Иначе говоря, не надо решать неуместных задач. Однако в жизни не все так просто — всегда нужен компромис и разумный баланс. Поясню на примере той же toUpper. Во времена разработки STL было ясно, что в мире существует не только Английский алфавит и не только 7-битовая ASCII кодировка, следовательно толку от toUpper будет мало (для простоты мы не принимаем в расчет locale, ctype, etc). Нужен некий обобщенный механизм, позволяющий — приложив малую толику усилий — достичь нужного результата. Я не утверждаю, что это хорошо, я лишь утверждаю, что в STL именно такой принцип и используется. Это имеет и преимущества и недостатки. Главное преимущество — когда появился Unicode, в STL не оказалось ничего, противоречящего этой новой сущности. Иними словами, STL успешно пережил нашествие Unicode. Главный же недостаток — именно в чрезмерной обобщенности, а именно в том, что все-таки необходимо приложить некие усилия для достижения результата. Но Unicode сам по себе — это тоже ограничение, например, только Китай за всю историю своего существования накопил более 64K иероглифоф (кстати, что будет означать toUpper применительно к Китайскому языку?). В то время, как в STL вполне можно реализовать строки на основе 24-битовых символов (если 32 покажется слишком дорого). Далее, кроме естественных алфавитов, в мире полно искусственных, например, ACTG (нуклеотиды) — всего-навсего 4 буквы, 2 бита на символ. Для него операция toUpper — вообще неуместна. Таким образом, строки в STL обладают значительно большей общностью и более широким спектром решаемых задач. Но с другой стороны, Unicode вполне удовлетворяет требованиям в 99% случаев. Грубо говоря (утрированно), с использованием Unicode остается лишь 1% нерешаемых задач, а с использованием STL — можно решить 99.9% задач, следовательно, остается 0.1%. И здесь все зависит от того, с какого конца считать — можно сказать, что разница составляет всего-навсего 0.9%, а можно — что разница в 10 раз.

Это я таким длинным образом пытаюсь вернуться к изначальному вопросу.

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

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

Метафорически можно сказать, что попытки описать функциональность наиболее полно — это попытки накормить весь мир рыбой, что является заведомо нереальным и бесперспективным ибо, когда у тебя кончится рыба, те же самые люди тебя и побъют. Гораздо более конструктивно — научить людей пользоваться удочками. Да, но при этом, люди конечно же сопротивляются — "не хочу удочку, хочу сразу рыбу". Здесь требуется определенное мужество — не поддаться соблазну и не сказать "на тебе рыбу, только отвяжись".
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 17.01.05 18:18
Оценка: :))) :)
Здравствуйте, McSeem2, Вы писали:

MS>И чем мне не нравятся ни Java, ни C# — так это тем, что порочная в своей сущности идея наследования в этих языках возведена в ранг неоспоримого догмата и единственного "правильного" способа написания программы. В C++ — это не более чем замшелая традиция, в Java и C# — центральная идея.


Забыл съязвить. Стиль программирования что в Java, что в C# (единственно, блин, верный) — это насоздавать кучерявых статических зависимостей, а потом пытаться "разрулить" всю эту квачу при помощи динамического полиморфизма и преобразований типов "бочка" к типам "селедка". Дела, дела...
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[5]: : Re[4]: [3]: : Re[2]: : True OOP
От: alexeiz  
Дата: 17.01.05 10:35
Оценка: 8 (1) +2
"Poudy" <12097@users.rsdn.ru> wrote in message news:990259@news.rsdn.ru
> Опять же, я даже не намекнул, что Алекс Степанов ничего не понимал в
> паттернах. Но реализовывал он их на шаблонах и процедурах (ну
> функторах). Оно для C++ неплохо, вероятно.
> Производительность, там, то да сё. Но работать с такой реализацией
> слегка, пусть на 0.01%, менее удобно, чем с "полнофункциональными"
> объектами.

Менее удобно? "Полнофункциональные" объекты, т.е OOP — полезная штука, но она не всесильна. Во многих случаях более подходящими оказываются другие парадигмы. Где ты был 10 лет назад, когда STL была спроективована? Думаешь не было OO библиотек для достижения той-же самой цели? Были и много. Но не выжили. Для C++ болезнь OOP — это уже давно пройденный этап. Другие языки прийдут к этому позднее (если вообще прийдут).

А вот, кстати, мнение самого Степанова:

Question:
This mean a radical change of mind from both imperative and OO thinking. What are the benefits, and the drawbacks, of this paradigm compared to the "standard" OO programming of SmallTalk or, say, Java?

Answer:
My approach works, theirs does not work. Try to implement a simple thing in the object oriented way, say, max. I do not know how it can be done. Using generic programming I can write [...]. Try doing it in Java. You can't write a generic max() in Java that takes two arguments of some type and has a return value of that same type. Inheritance and interfaces don't help. And if they cannot implement max or swap or linear search, what chances do they have to implement really complex stuff? These are my litmus tests: if a language allows me to implement max and swap and linear search generically — then it has some potential.

Posted via RSDN NNTP Server 1.9
Re[4]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.01.05 18:46
Оценка: 4 (2) +1
Здравствуйте, McSeem2, Вы писали:

MS>Да, как справедливо заметил AndrewVK, таким способом нельзя реализовать некоторые вещи.
Автор: AndrewVK
Дата: 06.01.05
Но ведь, если вдуматься, эти "вещи" как раз и являются следствием "зависания" на парадигме наследования. И причем, не просто "зависания", а использования идеи наследования неестественным образом — преобразованием от базового класса к производному (upcast или downcast — я их все время путаю, поскольку до сих пор не знаю, куда растет дерево наследования — вверх или вниз ).


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

Теперь по сути топика. Не хотел я писать, но уж коль ты мое сообщение помянул... Вобщем в тебе опять говорит страсть к черно-белому. Да, безусловно, при желании при помощи наследования можно накосячить будь здоров. Но это не значит что тут же надо объявлять наследование бесполезной вещью. Существует ряд задач, которые наследование решает неплохо. В основном эти задачи связаны с полиморфизмом. Можно конечно сказать что можно обойтись статическим полиморфизмом, но в случае компонентной среды это не так, что легко доказать. Некоторые правда идут дальше и говорят что компоненты никому не нужны и нужно писать исключительно самодостаточные монолиты, но это уже филосовский вопрос и спорить на эту тему я не хочу.
Тут как всегда проблема той самой несуществующей серебрянной пули. Статический полиморфизм, вынесение функционала вовне и прочие способы борьбы с наследованием тоже не лишены недостатков и за их достоинства приходится платить свою цену.
Ну и последняя мысль — стремление достигать гибкости и универсальности всегда и везде это очень опасная и вредная тенденция. Универсальность должна быть там и только там где есть немалый шанс что она будет востребована. Иначе в итоге проект наплодит кучу фреймворков, которые так и не будут востребованы, а основная функциональность будет реализована плохо.
... << RSDN@Home 1.1.4 beta 3 rev. 297>>
AVK Blog
Re[8]: : Re[4]: [3]: : Re[2]: : True OOP
От: Gaperton http://gaperton.livejournal.com
Дата: 17.01.05 13:37
Оценка: 1 (1) +2
_>Тут Степанов перебарщивает.
_>Такое ощущение, что ООП он значет только по Java.
Тут не в ООП дело . А в том, что функция max должна обладать параметрическим полиморфизмом по обоим аргументам. И всего-то.
Степанов под "ООП" очевидно имеет в виду обыкновенные статически типизированные ОО языки, в которых полиморфизм обеспечивается посредством (только) классов.

_>Например, вот реализация max в Smalltalk:

_>
_>Magnitude>>max: operand
_>    ^self < operand
_>        ifTrue:  [operand]
_>        ifFalse: [self]
_>


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

Что характерно, в любом не ОО динамически типизированном языке это будет записано еще проще, что-нибудь в духе
max( a, b )
{
   return a < b ? b : a;
}

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

В том же лиспе для max нет никакой необходимости использовать CLOS (как у тебя в примере) — можно просто функцию определить, работать будет также . Это у вас в смоллтоке другого выхода нет, как городить классы .
Re: True OOP
От: c-smile Канада http://terrainformatica.com
Дата: 16.01.05 19:19
Оценка: +3
Здравствуйте, Poudy, Вы писали:

P>Обсудить хочу следующий принцип для разработки ОО-библиотек:

P>

P>Каждый проблемный домен должен содержать свой центральный класс, содержащий наиболее полную (а не наиболее непротиворечивую) для данного домена функциональность.

P>Примеры использования этого принципа я вижу в System.Windows.Forms.Control и System.IO.Stream. Примеры из других библиотек приводить не буду, потому что толком в них не шарю.

Опять глобальные вселенские принципы приносящие щастье всем и бесплатно?
Опять 100 летняя война алой и белой розы: "Все есть объект" versus "Все есть handle/pointer"?

"Философского камня" нет.

Есть конкретные задачи/кластеры задач/библиотеки и методы их использования где работает динамический полиморфизм (виртуальное наследование)
Соответсвенно есть это все другое где статический полиморфизм (templates, everything is a abstract typename) "играет всеми гранями".
Есть еще функциональный подход — everything is a handle (HWND, HDC, void*, etc.)

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

Искусство проектирования и базовый принцип — стоять выше "ООП/не ООП" или конкретных языков
ибо цель проектирования (грамотного, нацеленного на результат) — создание оптимальных систем оптимальным образом.

Да, есть System.Windows.Forms.Control, а есть также HWND.
Да, есть System.IO.Stream, а есть FILE*...

Ну давайте поспорим что лучше...
Re[3]: : Re[2]: : True OOP
От: Павел Кузнецов  
Дата: 17.01.05 00:19
Оценка: +3
Poudy,

> В .Net есть ToUpper потому, что все строки в юникоде. А трансляция производится при помощи Encoding. И это правильнее, чем переводить translate'ом строку из неизвестной кодировки. А если в строку зашить указатель на кодировку, то опять нет проблем сделать ToUpper. Я сильно не прав?


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

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


Тебе кажется неправильно. Стандартная библиотека C++ вообще и STL в частности изобилует примерами различных паттернов проектирования. Например, применительно к std::translate, можно легко распознать Iterator и (сюрприз?) Strategy.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: : Re[4]: [3]: : Re[2]: : True OOP
От: _vovin http://www.pragmatic-architect.com
Дата: 17.01.05 12:51
Оценка: 5 (2)
Poudy wrote:

> A>А вот, кстати, мнение самого Степанова:

> A>

Question:
> A>This mean a radical change of mind from both imperative and OO thinking. What are the benefits, and the drawbacks, of this paradigm compared to the "standard" OO programming of SmallTalk or, say, Java?
> Это чистая правда.
>
> A>Answer:
> A>My approach works, theirs does not work. Try to implement a simple thing in the object oriented way, say, max. I do not know how it can be done. Using generic programming I can write [...]. Try doing it in Java. You can't write a generic max() in Java that takes two arguments of some type and has a return value of that same type. Inheritance and interfaces don't help. And if they cannot implement max or swap or linear search, what chances do they have to implement really complex stuff? These are my litmus tests: if a language allows me to implement max and swap and linear search generically — then it has some potential.


Тут Степанов перебарщивает.
Такое ощущение, что ООП он значет только по Java.

Например, вот реализация max в Smalltalk:
Magnitude>>max: operand
    ^self < operand
        ifTrue:  [operand]
        ifFalse: [self]


Magnitude является базовым классом для всех числовых типов, а так же для
даты и времени.

Тут еще может возникнуть вопрос, что реализация привязана к конкретной
иерархии. Но и он разрешим статической/динамической композиции классов,
реализуемой с помощью Traits/Mixins.

Если же взять CLOS, то там можно сделать что-то подобное
(defmethod max ((operand1 number) (operand2 number))
     (if (< operand1 operand2) operand2 operand1))


В нем ООП реализовано посредством generic functions, что снимает и
проблему симметрии получателя-параметров.
Posted via RSDN NNTP Server 1.9
Re[3]: True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 16.01.05 18:02
Оценка: 2 (2)
Здравствуйте, Poudy, Вы писали:

P>Тебя качнуло совсем в другую сторону от той, о которой я писал.


Значит я вообще не понял смысла вопроса.

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

P>Что ж теперь, назад в джунгли? Вообще забыть о наследовании? Это будетс слишком необдуманно и резко .

Ну, скажет так. В C++, единственное, для чего нужно наследование — это переопределить одну или несколько виртуальных функций. Ну еще — для спецификации исключений. Я тоже использую наследование в случаях отличных от этих. Но по здравому размышлению понимаю, что так я поступил просто-напросто от лени, и там где используется наследование — нужна инкапсуляция. У меня есть проект, хоть и небольшой, но довольно-таки сложный: http://www.antigrain.com/agdoc/index.html, где вообще нет наследования. При этом я могу утверждать, что он сделан в рамках классического ООП. И при этом — прекрасно расширяем.

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

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

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

MS>>Нужно заботиться не о "наиболее полной" функциональности, а прежде всего — о возможности расширения функциональности. А использование иерерхий классов в корне противоречит идее о возможностях расширения.

P>Вот вот тут вот (касаемо "в корне протеворечит") я совсем и категорически не согласен . Иногда противоречат некоторые реализации — вот моё мнение.

Я бы сказал практически все реализации. Значит идея наследования неверно понята всем миром и используется неправильно
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[9]: : True OOP
От: Cyberax Марс  
Дата: 19.01.05 07:50
Оценка: 1 (1) +1
LCR пишет:

> C>Багов с наследованием реализации в COM нет. Так как наследования

> C>реализации нет как класса.
> Я говорю "грабли", а не "баги". А грабли эти состоят в следующем:
> Предположим, у тебя есть объект, реализующий интерфейс I1. Разумеется
> у тебя есть реализация этих интерфейсов, скажем Impl1 и там
> реализована функция QueryInterface. Теперь нужен интерфейс I2, который
> включает I1. Но ты не можешь унаследовать реализацию Impl2 от Impl1,
> ибо Impl1::QueryInterface ничего не знает об интерфейсах,
> реализованных в Impl2. Ты вынужден тупо повторять реализацию Impl1.
> (Хорошо хоть, шаблоны есть: ).

Тут ошибка. QI, который находится в IUnknown, реализуется ТОЛЬКО одним
объектом. То есть всегда будет вызываться QI у Impl2, который уже знает
о всех интерфейсах. Это, кстати, используется при аггрегировании
объектов — вызовы QI от аггрегированного интерфейса получает
аггрегирующий объект. Можно использовать и C++-наследование для
реализации COM'а.

Наследования coclass'ов нет, так как это сложно сделать языко-независимо.

> C>COM — это просто стандарт на расположение методов в vtbl.

> Ну здесь ты чуть слукавил — это немножко больше

Ну подумаешь, детали

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[15]: : True OOP
От: Cyberax Марс  
Дата: 19.01.05 17:17
Оценка: 1 (1) +1
AndrewVK пишет:

> MS>Забавно. COM стал паровой машиной на современном уровне развития. А

> вот CORBA, которая значительно старше и является значительно более
> низкоуровневым средством чем COM, живет и помирать не собирается (в
> мире Java, например).
> Вот именно что низкоуровневым. CORBA предназначена для создания OO RPC.

Как и COM...

> А СОМ это способ создания КО-программ на разных языках. Java, о

> которой ты упомянут, имеет собственную компонентную модель, ни на
> каком уровне не являющейся CORBA.

COM не предназначен, а _позволяет_ создавать КО-программы, благодаря
_стандартизованному_ набору интерфейсов для взаимодействия визуальных
компонент ("COM — это средство, OLE — протокол" (с) Брокшмидт).

В CORBA тоже есть стандартизованные сервисы, например, Trading Service
или Persistance Service, которые ТОЖЕ позволяют писать КО-программы.
Просто CORBA до недавнего времени (GTK) не прикладывали к разработке
GUI. Принципиальных препятствий, опять же, нет.

> MS> И никто не говорит, что CORBA является паровой машиной в

> современном мире фотонных двигателей. На примере COM — очень хорошо
> виден "инженерный" подход Microsoft:
> Ну да, конечно, во всем опять виновата МС. Хорошо, какую еще ты знаешь
> технологию создания компонентов?

GNOME (GNU Network Object Model), QT, Java Beans, Tcl/Tk...

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[17]: : True OOP
От: Cyberax Марс  
Дата: 20.01.05 09:41
Оценка: 1 (1) +1
AndrewVK пишет:

> AVK>>Вот именно что низкоуровневым. CORBA предназначена для создания

> OO RPC.
> MS>Это очень примитивное представление, лишь один аспект.
> Но я что то не видел чтобы CORBA использовали для создания компонентов
> внутри одного процесса.

Ты много чего не видел CORBA — протоколонезависимая, поэтому во всех
нормальных ORB есть локальный протокол.

> MS>CORBA тоже является средством коммуникации между программами на

> разных языках. Без заявлений о всеобщем "щасте", поэтому и более
> низкоуровневым.
> Хорошо. Как называется технология, позволяющая скажем создавать GUI из
> CORBA-компонент? Нет, про CORBA 3.0 я знаю, но вот нормальная
> реализация ее где нибудь есть?

CORBA 3.0 — это стандарт на _сервисы_. Стандарт на протокол реализован
кучей вендоров, они даже интероперируют весьма неплохо. А GUI-компоненты
на CORBA — посмотреть можно в GNOME.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[3]: : True OOP
От: Gaperton http://gaperton.livejournal.com
Дата: 17.01.05 14:02
Оценка: +2
Здравствуйте, Poudy, Вы писали:

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


G>>Вообще-то в std::string нет toUpper/toLower совсем не потому, что кто-то забый ее туда добавить. Предполагается что ты воспользуешься стандартным алгоритмом transform и соответствующей функцией. И сделано так не случайно. В этом проявляется другой принцип проектирования, противоположный тому, который ты предлагаешь. Жизнь непростая штука


P>Хороший принцип? Если ты о том же, о чем говорил McSeem2, то это всего лишь вариант реализации, а не принцип.

Это именно принцип, я не ошибся.

P>В .Net есть ToUpper потому, что все строки в юникоде. А трансляция производится при помощи Encoding. И это правильнее, чем переводить translate'ом строку из неизвестной кодировки. А если в строку зашить указатель на кодировку, то опять нет проблем сделать ToUpper.

"правильнее" — не технический аргумент. Это вера. А вот технические аргументы:

Дизайн, сделаный этому принципу, обладает рядом очевидных практических преимуществ. translate c toupper (которая, кстати, может тоже быть полиморфной, и работать корректно как на unicode символах, так и на обычных) отработает корректно не только на строке, но и вообще на любом контейнере, где лежат символы. Принцип замечательный — у тебя возможностей комбинировать функционал больше на порядок. Ты можешь добавить свою реализацию хитрых строк в отдельном классе, и получишь для нее toupper автоматически. Не заморачиваясь организацией иерархии наследования.

P>Я сильно не прав?

Сам думай
Re[7]: : True OOP
От: Cyberax Марс  
Дата: 18.01.05 09:46
Оценка: 5 (1)
WolfHound пишет:

> Я использую лишь наследование интерфейсов. (*) Наследование реализации

> в данной иерархии спользовано лишь для INode и INodeWithChildren

Ну так и это нафиг убери. У тебя же интерфейсы, зачем делать
INodeWithChildren? Сделай интерфейс IChildrenContainer.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
True OOP
От: Poudy Россия  
Дата: 16.01.05 12:20
Оценка: 4 (1)
Хочу вынести на обсуждение одну спорную идею о принципах программирования объектов.

Долго размышлял над сутью споров о статической/динамической типизации, использовании шаблонов и C++ vs динамические языки. И в данной ветке мне не хочется в очередной раз пережевывать "разные языки для разных задач". Есть вполне прагматичная и правильная точка зрения профессионалов и полиглотов о том, чтобы использовать разные языки и подходы (прототипируем на Smalltalk, переписываем на С++), тут всё ясно.

Часто вспоминаю слова Алана Кея о том, что всё есть объект, и как важна идея посылки сообщения. Для меня очевидно, что исключения из правил "объектности" несут проблемы во многих языках. Примеры: в C++ класс — это не объект (как Type в C#), bool — это не объект и в C++ и в Java.

В свою очередь для ОО-библиотек есть похожие несуразности, которые я отношу к звеньям той же цепи:
1. Библиотека не последовательна в функциональности классов. Пример: в System.Windows.Forms.MenuItem нет Tag, а в std::string нет toUpper/toLower.
2. Иерархия классов странная (больше относится к custom библиотекам). Каждое десятый пост в форуме Проектирование о том, как спроектировать очередную странную иерархию, где Readonly, Admin, Web и прочая функциональность сильно переплетены, и автор непременно хочет заморозить всё это в статичном виде.

Обсудить хочу следующий принцип для разработки ОО-библиотек:

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

Примеры использования этого принципа я вижу в System.Windows.Forms.Control и System.IO.Stream. Примеры из других библиотек приводить не буду, потому что толком в них не шарю.

Как аргумент в защиту принципа могу привести умственный опыт: представим библиотеку, в которой работа с файлами ведется при помощи InputSystemFile, OutputTextFile, IONetworkFile, SequentialBinaryIOFile и т.д. При этом абстрактный класс (или интерфейс), лежащий в корне иерархии, содержит только Name (getName) и Close() (close()).
Re[2]: True OOP
От: Poudy Россия  
Дата: 16.01.05 16:41
Оценка: 1 (1)
Тебя качнуло совсем в другую сторону от той, о которой я писал.

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

P>>В свою очередь для ОО-библиотек есть похожие несуразности, которые я отношу к звеньям той же цепи:

P>>1. Библиотека не последовательна в функциональности классов. Пример: в System.Windows.Forms.MenuItem нет Tag, а в std::string нет toUpper/toLower.

MS>Ничего странного в этом нет. Функциональности на все-про-все не напасешься.

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

MS>Обычно начинающие лихо делают новый класс-потомок и добавляют туда требуемые функции. ...

MS>...Наиболее правильным было бы сделать просто функцию toLower(std::string& s).
Согласен.

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

Что ж теперь, назад в джунгли? Вообще забыть о наследовании? Это будетс слишком необдуманно и резко .

MS>Применительно к std::string нет никакой разницы между записями str.toLower() и toLower(str). Для данного случая, расуждения о важности идеи посылки сообщений — не более чем демагогоия.

Как-то ты.... эта-а.. стоп. str.toLower() — это не важная посылка сообщения. Посылка сообщения — это инкапсуляция + полиморфизм. Инкапсулируется способ исполнения запроса и позволяется, чтобы он был разным для разных объектов. Важность посылки сообщения была вообще не о str.toLower(), а о том, чтобы расширять функциональность по-возможности паттерном стратегия или мост. А также применительно к динамическим языкам, которые не требуют явного указания, может ли объект принять указанное сообщение, и потому удобны для быстрого прототипирования.

MS>Можно возразить, что например, требуется сделать синхронизированную, thread safe строку. ... Здесь нужна инкапсуляция с аккуратным переопределением всех методов. Много писать? Да, много. Но все другие варианты — еще хуже.

Да, всё верно.

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

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


P>>Обсудить хочу следующий принцип для разработки ОО-библиотек:

P>>

P>>Каждый проблемный домен должен содержать свой центральный класс, содержащий наиболее полную (а не наиболее непротиворечивую) для данного домена функциональность.


MS>Понятие "наиболее полная функциональность" — это абсурд в силу принципов организации нашей Вселенной... Так, я это уже говорил...

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

MS>Нужно заботиться не о "наиболее полной" функциональности, а прежде всего — о возможности расширения функциональности. А использование иерерхий классов в корне противоречит идее о возможностях расширения.

Вот вот тут вот (касаемо "в корне протеворечит") я совсем и категорически не согласен . Иногда противоречат некоторые реализации — вот моё мнение.
Re[4]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 18:28
Оценка: 1 (1)
Здравствуйте, McSeem2, Вы писали:

P>>Выходит, по твоему TRUE OOP — это язык без статического наследования? Или Python?

MS>Я бы сказал, что вообще идея наследования объектов — порочна в самой своей сущности. Идея объектов, как черных ящиков, передача сообщений, интерфейсы, полиморфизм — это все правильно, ибо достаточно хорошо отражает реальные задачи и реальный мир. ... Мое утверждение таково: полиморфизим — хорошо, наследование — плохо.

В этом утверждении я позволю себе с вами не согласиться, да. Наследование интерфейсов и реализации привносит в программную модель определенную структуру. Статический взглдя очень важен, не даром многие программисты жалуются на непрозрачность кода с использованием паттернов. Алан Кей вносит идею непосредственного взаимодействия с программой в runtime. Но это не выполнимо для большого количества систем. Работа с серьезной системой в runtime при наличии правильной инкапсуляции перестает приносить искомую пользу. В пределе это больше становится похоже на работу с реальным объектом (или Windows): "Это работает, но, черт возьми, я не представляю как." Почитайте Страуструпа наконец!


MS>Да, как справедливо заметил AndrewVK, таким способом нельзя реализовать некоторые вещи.
Автор: AndrewVK
Дата: 06.01.05
Но ведь, если вдуматься, эти "вещи" как раз и являются следствием "зависания" на парадигме наследования. И причем, не просто "зависания", а использования идеи наследования неестественным образом — преобразованием от базового класса к производному (upcast или downcast — я их все время путаю, поскольку до сих пор не знаю, куда растет дерево наследования — вверх или вниз ). На мой взгляд, как только возникает необходимость в таком преобразовании, значит что-то здесь не так, и это является серьезной уликой попыток решать неуместные задачи.

Опять неверно. Программа без классов и наследования плохо поддается статическому анализу. Практически очень сложно ввести на ней какие-нибудь метрики оценки качества или сложности. Также тяжело сделать, к примеру, code assistance. Всё работает хорошо только до тех пор, пока программа целиком работает в памяти (или у тебя в голове . Если же она просто написана на листе бумаги, всё кастрофически усложняется. В реальности, приходится загружать значительну часть программы на Smalltalk или Python в человеческую память, чтобы разобраться в принципах её работы.

MS>Иными словами, я бы однозначно исключил из понятия ООП понятие наследования, как полностью себя дискредитировавшее. И чем мне не нравятся ни Java, ни C# — так это тем, что порочная в своей сущности идея наследования в этих языках возведена в ранг неоспоримого догмата и единственного "правильного" способа написания программы. В C++ — это не более чем замшелая традиция, в Java и C# — центральная идея.

Я бы не сказал, что центральная. Но определенно одна из любых двух первых.
Re[5]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 18:42
Оценка: 1 (1)
Здравствуйте, WolfHound, Вы писали:

WH>Гм. Я хочу поговорить об этом...

WH>Есть модель некоторого дерева ноды которого могут иметь разные типы. Например файловая система есть несколько типов нод: папка, текстовый фаил, графический фаил, архив... Папка, архив... имеют детей.
WH>Допустим нам надо отобразить это дерево в пользовательском интерфейсе. Выглядить это должно так: с права дерево, а с лева отображение текущей ноды.
WH> [skipped]
WH>Внимание вопрос: А как это сделать без наследования, определения конкретного типа и даункастов?

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

В данном случае, скорее всего, нужнен только один класс — Узел.

Нужно использовать "поле типа", которое бы возвращало "тип" данного узла в виде объекта Тип. Поскольку Тип является объектом, их может быть сколько угодно. В Типе задается всё, что нужно знать о типе.

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

В остальном же лучше нашпиговать класс Узла всеми часто используемыми и полезными методами и свойствами. Включая Preview(), IsImage, Extention, HaveExtention, IsReadOnly и т.д.
Re[5]: : True OOP
От: Павел Кузнецов  
Дата: 17.01.05 21:47
Оценка: 1 (1)
WolfHound,

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


Если вопрос не праздный, то полагаю, что тебе может показаться очень интересной книга: John Vlissides. Pattern Hatching: Design Patterns Applied (Джон Влиссидес. Применение шаблонов проектирования. Дополнительные штрихи) — заметную часть книги занимает анализ как раз аналогичного случая. Краткий вывод такой: в данной ситуации оправдано использование "жирных" интерфейсов.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[9]: : True OOP
От: Poudy Россия  
Дата: 18.01.05 11:40
Оценка: 1 (1)
Здравствуйте, WolfHound, Вы писали:

P>>Зачем ты вообще сделал их элементами дерева?

WH>За тем что логика модели такова что они являются элементами дерева.
Хорошо.

P>>IMHO, если "состоять в дереве" не является их прямой функцией,

WH>Правда? А по моему очень даже является.(в данном случае дерево это не отображение, а структура данных)
Я не знаю твоей конткретной задачи. Насчет примера ты сам говорил, что он искусственный. Если по-твоему являются, пусть будет так.

P>>то дерево нужно сделать отдельно от этих типов.

WH>Зачем? Хотя то дерево которое используется в System.Windows.Forms.TreeView сделано действительно отдельно от модели (и для оптимизации в свойстве Tag хранится ссылка на объект модели) ибо как я уже говорил отображений несколько...
Ок ок.

P>>Хранить объект в Tag или чем там еще узла дерева и синхронизить структуру дерева с объектами когда надо. Дерево строишь билдером, синхронизируешь состояние листенерами. Грамотное и гибкое решение.

WH>При отображении этого дела в TreeView я именно так и поступаю.
WH>Но никак не могу понять как ты предлагаешь строить дерево по не организованным объектам?
Я имел в виду: зачем тебе одно общее явное дерево и объекты в виде его узлов.
А строить билдером. Так или иначе, они всё равно организованы. Билдер — просто вариант реализации, с теми же даункастами. Однако я уже вижу, что перед тобой стоит другая задача.

WH>Как ты предлагаешь гарантировать целостность модели? В смысле не дать нарушить инвариант модели какимнибудь левым действием отображения. У меня за целостностью следит сама модель. Как я уже говорил отображений несколько и следить за целостностью модели в каждом из них Причем большая часть контроля выполняется компилятором C# и рантаймом .НЕТ благодоря именно тонким интерфейсам(ну не сможешь ты заменить колеса у кошки... ну нет в ее интерфейса таких функций... и получить интерфейс машины у кошки тоже ни кто не даст).

Целостность модели, если она проверяется моделью, нарушить всё равно нельзя. Просто я не достаточно ясно выразился про дерево. Ты хочешь древовидную структуру. Я отметил, что совсем не обязательно давать для этого объектам общий интерфейс узла.

WH>>>ЗЗЗЫ В моем случае интерфейс получится ооочень толстым. А самое главное я не вижу ни одного плюса.

P>>Толще, чем у Control? Сомневаааюсь.
WH>Если ты про System.Windows.Forms.Control то он то тут причем?
WH>А в моем случае в место нескольких тонких интерфейсов которые имеют между собой меньше общего чем машина, картошка и кошка... получится один толстый которые все это совмещает? Зачем?
Я не знаю, сколько там общего у твоих объектов . Если всё так, то нет, не нужно писать большой интерфейс.

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

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

Существует 3 необходимых функциональности:
1. Построение дерева.
2. Просмотр.
3. Выполнение действий.

Я считаю, что декомпозицию в классы необходимо делать по функциональному принципу. Буквально: каждый отвечает за своё.

В данном случае у нас есть несколько таких функций или обязанностей, лежащих на каждом объекте.
1. Содержаться в контейнере.
2. Быть контейнером элементов или, точнее — обслуживать контейнер элементов. Управлять им.
3. Предоставлять расширенную информацию о себе в текстовом виде + картинки, иконки.
4. Выполнять общие функции, вроде DefaultAction.
5. Выполнять специфические функции.

Соответственно, в системе я бы завел минимум 5 классов:
1. Элемент контейнера — извещает контейнер о добавлении и удалении себя из него (friend || internal методы).
2. Контейнер — извещает элементы о добавлении и удалении их из себя (friend || internal методы), наследован от элемента.
3. Дескриптор, содержащий описание некоторого объекта.
4. Объект файловой системы, содержащий Name, Path и DefaultAction.
5. Конкретный файл.
(на самом деле, если дерево не предполагается заюзать повторно, классы 1 и 4 можно объединить в один)

Рассморим всё по порядку с чувством, с толком, с расстановкой

В C# нет множественного наследования и мы можем выбрать только один класс в качестве корня общей иерархии, поместив в него реализации наиболее общих и нужных методов. Я говорю не об интерфейсе рута, а именно о готовой реализации.
В данном случае можно выбрать (1), (4) или их join.

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

А можно сделать, чтобы контейнер также и хранил элементы. Для этого в его интерфейсе должны присутствовать ICollection, IList, а также метод CanAdd(Accept)Item(Element). Т.е. контейнер позволяет потомкам производить валидацию данных.

Дескриптор
При фиксированном пользовательском интерфейсе вводить дескриптор нет смысла. Все его свойства и методы можно легко запихнуть в Элемент или Объект файловой системы. Но! Если у нас существует поддержка многих языков для подписей к файлам или возможность менять иконку для отображения, ну и так далее. То лучше воспользоваться Дескриптором.

На это есть как минимум 2 причины:
1. Описание требуется другим системам и таких систем может быть много. Т.е. потенциально требуется неизвестное количество типов описаний.
2. Вынесение дескриптора в отдельную функциональность и класс позволяет реализовать несколько гибких механизмов получения и настройки описания, чем простое element.DescriptionString.

Имея класс Дескриптора, мы можем создать класс Сервис Дескрипторов, конструирующий описания для переданных ему объектов. Сервис дескрипторов может делать следующие вещи:
1. Просто конструировать объект описания по значениям свойств объекта и атрибутов, прикрепленных е его типу.
2. Возвращать default описание или заполнять недостающие значения.
3. Хостить в себе chain of responsibility для конструирования или модификации описания.
4. Рассылать события об изменении описания для определенного типа объектов или конкретного объекта.

Объект файловой системы
Ну понятно: содержит общие свойства и методы. Но даже тут есть несколько тонкостей.

Во-первых: как я уже говорил, можно слить его с Элементом. Если не сливать, то появляется проблема отсутствия множественного наследования при необходимости быть ОбъектомФС и Папке (контейнеру) и Файлу(элементу). Проблема решается агрегированием. Так или иначе, обращение к элементам папки будет проходить не так: folder[6], а так: folder.Items[6].

Агрегированием сущностей и внутренним связыванием с ними решается много проблем, когда есть проблемы с множественным наследованием. Итак мы имеем в дереве одни только элементы, но некоторые из них содержат в себе контейнеры элементов. Для нетипизированного обхода дерева остается всё тот же implicit IEnumerable на всех элементах.

Во-вторых: DoDefaultAction желательно делегировать или хотя бы дать возможность для делегирования. Для выполнения DoDefaultAction желательно использовать медиатор. Этот медиатор будет либо передавать сразу управление ОбъектуФС, который его(медиатор) хостит. Либо вызывать сервис в определенном контексте, получая этот контекст либо из thread, либо обходя в его поиске Parent'ы, либо вызывая синглтон (который также может пройтись по Parent'ам для выяснения соответствия контексту).

Конкретный файл
Ну тут всё просто. То, что не вошло ни в одну систему, не пользуется напрямую GUI'ем и не присутствует в контекстных меню, ощутимо находится здесь в виде типизированных публичных методов и свойств и юзается при создании элементов, а также в редких случаях после downcast'а в кривых обработчиках.

Надеюсь, что написал подробно и понятно. Жду от тебя неленивого ответа .
Re[7]: : True OOP
От: Cyberax Марс  
Дата: 18.01.05 11:52
Оценка: 1 (1)
LCR пишет:

> КЕ>На мой взгляд наиболее расширяемым (и при этом недорогим) решением

> является введение в INode функции а-ля QueryInterface. Отсюда следует
> что все-же придется ручками перечислять интерфейсы в реализации
> QueryInterface. Кроме того каждому интерфейсу в рантайме должен
> соответствовать некий идентификатор. Короче очень похоже на запрос
> интерфейса в COM.
> Одна из проблем COM — это то что от любого интерфейса нужно уметь
> шагнуть к любому другому интерфейсу, при этом объект остаётся как-бы
> "за кулисами" и к нему доступа нет. Отсюда известные грабли с
> наследованием реализаций.

Багов с наследованием реализации в COM нет. Так как наследования
реализации нет как класса.

COM — это просто стандарт на расположение методов в vtbl. Встроенными
средствами _С++_ нельзя приспособить наследование так, чтобы методы
располагались в vtbl в правильном порядке для COM. Но принципиальных
проблем с наследованием реализации в COM нет, есть даже и ее частичная
имплементация в виде аггрегирования.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[6]: : Re[4]: [3]: : Re[2]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 11:53
Оценка: :)
Здравствуйте, alexeiz, Вы писали:

A>Менее удобно? "Полнофункциональные" объекты, т.е OOP — полезная штука, но она не всесильна. Во многих случаях более подходящими оказываются другие парадигмы. Где ты был 10 лет назад, когда STL была спроективована?

Я тогда еще не родился.

A>Думаешь не было OO библиотек для достижения той-же самой цели? Были и много. Но не выжили. Для C++ болезнь OOP — это уже давно пройденный этап. Другие языки прийдут к этому позднее (если вообще прийдут).

А что ты имеешь тут в виду под ООП? Наследование?

A>А вот, кстати, мнение самого Степанова:

A>

Question:
A>This mean a radical change of mind from both imperative and OO thinking. What are the benefits, and the drawbacks, of this paradigm compared to the "standard" OO programming of SmallTalk or, say, Java?
Это чистая правда.

A>Answer:
A>My approach works, theirs does not work. Try to implement a simple thing in the object oriented way, say, max. I do not know how it can be done. Using generic programming I can write [...]. Try doing it in Java. You can't write a generic max() in Java that takes two arguments of some type and has a return value of that same type. Inheritance and interfaces don't help. And if they cannot implement max or swap or linear search, what chances do they have to implement really complex stuff? These are my litmus tests: if a language allows me to implement max and swap and linear search generically — then it has some potential.

Ну заете ли... Можно и так сказать:

Попробуйте-ка реализовать динамический вызов Smalltalk или полиморфный стек StrongTalk на шаблонах C++, и чтобы скорость была приемлемой. Ха! Обломитесь. Мой подход работает, а их — нет. И вообще, для меня критекрием хорошего языка является то, что он называется Smalltalk. Если язык называется Smalltalk — в нем есть потенциал.


Он тут явно использует семантическую подмену "Inheritance and interfaces don't help" на "Inheritance and interfaces are useless".
Re[9]: Согласен
От: _vovin http://www.pragmatic-architect.com
Дата: 17.01.05 13:33
Оценка: +1
> Но всё-таки я хотел обсудить детали реализации на C++/C#/Java.
> Выработать совет при построении иерархий в этих языках, считая что template'ов как бы нет в природе.

Совет — нечего мучаться.
Posted via RSDN NNTP Server 1.9
Re[9]: Согласен
От: Cyberax Марс  
Дата: 17.01.05 13:36
Оценка: +1
Poudy пишет:

> Но всё-таки я хотел обсудить детали реализации на C++/C#/Java.

> Выработать совет при построении иерархий в этих языках, считая что
> template'ов как бы нет в природе.

В Java шаблоны заменяются на интерфейсы, абстрактные алгоритмы работают
уже через эти интерфейсы. Сами алгоритмы реализуются в static-методах
классов. Смотри java.util.Collections (методы сортировки, например).

В общем, все почти как в STL...

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

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


P>>>Я сильно не прав?

G>>Сам думай
P>Я-то думаю... да думаю ни кто тут меня не понимааает .
P> А ваще это как закономерность уже. Стоит написать "такая-то вещь кажется неудобной", как нарвешься на "Ах, ты не любишь шаблоны??!! Ты не любишь C++??????!!! Да что ты понимаешь! Ты быть может еще и UML не любишь? С проектированием не дружишь? Ты что, имеешь в виду, что .net лучше всех? Зачем ты написал, что любишь microsoft?! Отвечай, зачем ты зареал милиционера, убийца!!!!!"

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

P>P.S.: всё исключительно на правах шутки.

аналогично.
Re[5]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 17.01.05 20:57
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

WH>Внимание вопрос: А как это сделать без наследования, определения конкретного типа и даункастов?


Ты будешь мощно смеяться — не знаю как. И никто толком не знает.
Рискну модифицировать и продолжить иерархию.

WH>INode
WH>INodeWithChildren : INode
WH>IFolder : INodeWithChildren
WH>IArchive : INodeWithChildren
   IFile : INode
WH>ITextFile : IFile
WH>IGraphicFile : IFile


ICompresedFile : IFile
ICompressedTextFile : ITextFile, ICompessedFile
IRasterGraphicFile : IGraphicFile
IVectorGraphicFile : IGraphicFile
ICompressedRasterGraphicFile : IRasterGraphicFile, ICompressedFile
ICompressedVectorGraphicFile : IVectorGraphicFile, ICompressedFile


Таким образом, мы очень быстро (я бы сказал, очень-очень быстро) приходим к совершенно запутанной и неудобоваримой схеме наследования. AndrewVK упрекнул
Автор: AndrewVK
Дата: 17.01.05
меня в том, что я не подменяю понятие "наследование интерфейсов" понятием "наследование классов":

AVK> 1) В моем примере преобразования от базового к производному не было


Упрек безусловно справедливый, если придерживаться рамок C# или Java. Но наследование интерфейсов — все равно остается наследованием. И даункастинг остается даункастингом со всеми вытекающими последствиями — статическими (compile time) зависимостями, которые буквально "цементируют" всю систему и нет никакой возможности что-то использовать (code reuse) без вытаскивания всей цепочки наследования до самого корня. А при множественном наследовании "этого" получается очень и очень много.

Отвечая на вопрос, скажу, что я бы предпочел схему "примерки" интерфейсов без какого-либо наследования. У нас есть одна единственная сущность — нода. Мы берем эту ноду и пытаемся "примерять" разные интерфейсы, существующие независимо от имплементации. Ну, примерно, как в Хероне. Вот еще-бы как-то это сделать совсем динамически...
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[6]: : True OOP
От: Poudy Россия  
Дата: 18.01.05 05:36
Оценка: -1
Здравствуйте, McSeem2, Вы писали:

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

MS>А программа с классами, но без наследования?

Это то же самое, как если бы классов не было вовсе.
Re[8]: : True OOP
От: WolfHound  
Дата: 18.01.05 09:46
Оценка: +1
Здравствуйте, Poudy, Вы писали:

P>Зачем ты вообще сделал их элементами дерева?

За тем что логика модели такова что они являются элементами дерева.
P>IMHO, если "состоять в дереве" не является их прямой функцией,
Правда? А по моему очень даже является.(в данном случае дерево это не отображение, а структура данных)
P>то дерево нужно сделать отдельно от этих типов.
Зачем? Хотя то дерево которое используется в System.Windows.Forms.TreeView сделано действительно отдельно от модели (и для оптимизации в свойстве Tag хранится ссылка на объект модели) ибо как я уже говорил отображений несколько...
P>Хранить объект в Tag или чем там еще узла дерева и синхронизить структуру дерева с объектами когда надо. Дерево строишь билдером, синхронизируешь состояние листенерами. Грамотное и гибкое решение.
При отображении этого дела в TreeView я именно так и поступаю.
Но никак не могу понять как ты предлагаешь строить дерево по не организованным объектам?
Как ты предлагаешь гарантировать целостность модели? В смысле не дать нарушить инвариант модели какимнибудь левым действием отображения. У меня за целостностью следит сама модель. Как я уже говорил отображений несколько и следить за целостностью модели в каждом из них Причем большая часть контроля выполняется компилятором C# и рантаймом .НЕТ благодоря именно тонким интерфейсам(ну не сможешь ты заменить колеса у кошки... ну нет в ее интерфейса таких функций... и получить интерфейс машины у кошки тоже ни кто не даст).

WH>>ЗЗЗЫ В моем случае интерфейс получится ооочень толстым. А самое главное я не вижу ни одного плюса.

P>Толще, чем у Control? Сомневаааюсь.
Если ты про System.Windows.Forms.Control то он то тут причем?
А в моем случае в место нескольких тонких интерфейсов которые имеют между собой меньше общего чем машина, картошка и кошка... получится один толстый которые все это совмещает? Зачем?
Если с Control в принципе понятно чем руководствовались авторы создавая толстый интерфейс (хотя и тут есть с чем поспорить но это тема для отдельного флейма) то в моем случае нет вобще никаких предпосылок создовать толстый интерфейс
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.01.05 10:45
Оценка: +1
Здравствуйте, Poudy, Вы писали:

P>Я не согласен с AndrewVK, что наследование классов (классов?) необходимо для полиморфизма. Для динамических языков без наследования вопрос полиморфизма вообще не стоит (как в JavaScript). Полиморфизма можно добиться одними интерфейсами. Возможно, он имел в виду другой полиморфизм — полиморфизм обобщенных алгоритмов, выражаемых в виде класса.


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

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


Не только. Наследование (в статически типизируемых языках) это как минимум две вещи — наследование интерфейса и наследование реализации. Главная хитрость — уметь применять оба аспекта таким образом, чтобы не возникало описанных нехороших эффектов.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[7]: : True OOP
От: Костя Ещенко Россия  
Дата: 19.01.05 00:33
Оценка: +1
Здравствуйте, AndrewVK, Вы писали:

КЕ>>На мой взгляд наиболее расширяемым (и при этом недорогим) решением является введение в INode функции а-ля QueryInterface. Отсюда следует что все-же придется ручками перечислять интерфейсы в реализации QueryInterface. Кроме того каждому интерфейсу в рантайме должен соответствовать некий идентификатор.


AVK>Фактически полное дублирование рефлекшена.


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

При отсутствии рантайм-рефлекшена подобная функция-член интерфейса является неплохим решением (написано в C++ стиле):
// функция, адрес которой лежит в vtbl Херон-интерфейса 
UnspecifiedItfRef QueryInterface(ItfId id)
{
  if( id == SomeItf::Id ) return Ref<SomeItf>(this);
  else if( id == SomeAnotherItf::Id ) return Ref<SomeAnotherItf>(this);
  else return NULL;
}

// типобезопасный шаблон - обертка над предыдущей функцией
template<class ItfType>
ItfType QueryInterface()
{
  return static_cast<ItfType>( QueryInterface(Itf::Id) );
}


AVK>И что это даст?


Возможность приводить интерфейсную ссылку к интерфейсной ссылке другого типа за счет явного указания поддерживаемых интерфейсов, без составления огромной таблицы соответствия классов интерфейсам. Если оно надо. Вполне годится для создания компонентов.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[13]: : True OOP
От: Костя Ещенко Россия  
Дата: 19.01.05 11:05
Оценка: +1
AndrewVK wrote:

> ПК>Легко. Достаточно реализовать ставшую классической функцию QueryInterface.

>
>
> Это не КОП, это изврат. СОМ-образные решения на современном уровне развития никуда не годятся и выглядят примерно как корабли с паровой машиной сегодня.

Почему не годятся?

Если бы реализация QI могла быть сгенерирована компилятором при минимальной набивке текста, и вызов QI выглядел бы как просто как кастинг, это было бы достаточно современным? Ведь то, что например using скрывает Dispose(), не делает его несовременным.

[]
Posted via RSDN NNTP Server 1.9
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[13]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 19.01.05 16:31
Оценка: +1
Здравствуйте, AndrewVK, Вы писали:

ПК>>Легко. Достаточно реализовать ставшую классической функцию QueryInterface.


AVK>

AVK> Это не КОП, это изврат. СОМ-образные решения на современном уровне развития никуда не годятся и выглядят примерно как корабли с паровой машиной сегодня.

Забавно. COM стал паровой машиной на современном уровне развития. А вот CORBA, которая значительно старше и является значительно более низкоуровневым средством чем COM, живет и помирать не собирается (в мире Java, например). И никто не говорит, что CORBA является паровой машиной в современном мире фотонных двигателей. На примере COM — очень хорошо виден "инженерный" подход Microsoft:
Наворотить кучу в бесплодных попытках решить задачу космического масштаба, после чего, убеждать весь мир в том, как это полезно для здоровья (ешь, ешь!). Далее, через некоторое время, объявить, что эта куча была (выражаясь политкорректно) стратегической ошибкой. И тут же начать воротить новую кучу, объявляя ее счастием для всех людей. Есть опасения, что дот-нет FW тоже будет объявлен страдегической ошибкой — это лишь вопрос времени.

Из книжки Алена Голуба:

Ричард Рашид (разработчик Mach — варианта ОС UNIX) выступил
несколько лет назад с основным докладом на конференции разработчиков
Microsoft. Его главный смысл состоял в том, что слишком большая
сложность как в пользовательском интерфейсе, так и в программе является
единственной большой проблемой, стоящей перед проектировщиками и
пользователями программного обеспечения. По иронии, его речь была
произнесена спустя два дня после провалившейся попытки показать
нескольким тысячам очень толковых программистов, как программировать
разработанный Microsoft интерфейс OLE 2.0 — один из самых сложных
интерфейсов прикладного программирования, когда-либо мной виденных.
(OLE означает "связь и внедрение объекта". Стандарт OLE 2.0 определяет
интерфейс, который может использоваться двумя программами для
взаимодействия между собой определенным образом. Это действительно
объектная ориентация на уровне операционной системы).
Предыдущий оратор, который убеждал нас пользоваться библиотекой
Microsoft Foundation Classes (MFC), сказал нам, что поддержка OLE в MFC
"включает 20000 строк кода, необходимых для каждого базового
приложения OLE 2.0". Аудитория была ошеломлена не полезностью MFC,
а тем фактом, что для написания базового приложения OLE 2.0 требуется
20000 строк кода. Любой интерфейс такой сложности таит в себе изъян.

McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[5]: : True OOP
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.01.05 00:32
Оценка: +1
Здравствуйте, Cyberax, Вы писали:

C>Да, причем если я в STL захочу сделать toUpper/toLower для эльфийского

C>языка, транскрибированного арабскими буквами, то мне просто нужно будет
C>сделать специальный функтор, и я смогу сохранить consistent интерфейс. А
C>вот в .NET — никак.

Ага. Видимо именно по этому для 90% языков имеющихся в мире в .Net преобразование сделано, а "в STL захочу сделать" так и остается трепом.
... << RSDN@Home 1.1.4 beta 3 rev. 279>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: : True OOP
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.01.05 00:32
Оценка: :)
Здравствуйте, McSeem2, Вы писали:

MS>что разница составляет всего-навсего 0.9%, а можно — что разница в 10 раз.


После забега призедента США и нашего генсека ТАСС сообщил, что "в то время как наш генсек занял почетное второе место, призидент США пришел к финишу предпоследним".

А если серьезно, то сравнивать нужно именно усилия программистов. Рельно в дотнете вызвав ToUpper() ты получишь нужный результат в 99% случаев. А вот в С++ ты в 99% случаев получишь возможность врукопашную получить нужный результат в доволь натрахавшись с этим процессом. И только в одном проценте случаев ты получишь тот самый результат без траха.

ЗЫ

Не бабываем про долю шутки в шутках...
... << RSDN@Home 1.1.4 beta 3 rev. 279>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: True OOP
От: Poudy Россия  
Дата: 16.01.05 18:46
Оценка:
Здравствуйте, McSeem2, Вы писали:

P>>Что ж теперь, назад в джунгли? Вообще забыть о наследовании? Это будетс слишком необдуманно и резко .


MS>Ну, скажет так. В C++, единственное, для чего нужно наследование — это переопределить одну или несколько виртуальных функций. Ну еще — для спецификации исключений. Я тоже использую наследование в случаях отличных от этих. Но по здравому размышлению понимаю, что так я поступил просто-напросто от лени, и там где используется наследование — нужна инкапсуляция. У меня есть проект, хоть и небольшой, но довольно-таки сложный: http://www.antigrain.com/agdoc/index.html, где вообще нет наследования. При этом я могу утверждать, что он сделан в рамках классического ООП. И при этом — прекрасно расширяем.


С твоим проектом я хорошо знаком. Буквально сегодня днем читал обновления документации. Действительно, это вполне ОО библиотека, поскольку классы четко делегируют обязанности друг другу. Механизм обработки любого запроса изменяем и поток обработки данных хорошо контролируется и расширяется.

Ну а насчет наследования — если рассматривать только наследование реализации, то это и есть инструмент для "ленивых". Примерно такой же, как компилятор. Если же рассматривать наследование интерфейса, то просто в C++ очень всё перепутано с концепциями AI, и люди долго боролись за приведение мыслей в порядок. Java & C#, кто бы что не говорил, являются очень большой подвижкой в сторону нормальной работы с иерархиями (куча, object и interface).

MS>Именно! И если подумать дальше, то получится, что область применения наследования — очень и очень ограничена.

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

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

Смешно. .

P>>Вот вот тут вот (касаемо "в корне протеворечит") я совсем и категорически не согласен . Иногда противоречат некоторые реализации — вот моё мнение.

MS>Я бы сказал практически все реализации. Значит идея наследования неверно понята всем миром и используется неправильно
То, что MFC на твой взгляд неправильно понимает наследование, не покрывает все существующие системы. Кроме того, тут есть разница между AGG и MFC.
• Ты пишешь продукт, который можно встроить в чужой продукт. Строишь его расширяемым. Пишешь долго, но качественно.
• Чуваки из MS пишут фичу Windows. Им не нужно позволять другим кампаниям ничего встаивать или расширять. И пишут они в жутко замыленном режиме. Вот и всё.
Re[2]: True OOP
От: Poudy Россия  
Дата: 16.01.05 21:12
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Опять глобальные вселенские принципы приносящие щастье всем и бесплатно?

CS>Опять 100 летняя война алой и белой розы: "Все есть объект" versus "Все есть handle/pointer"?
CS>"Философского камня" нет.
CS>Есть конкретные задачи/кластеры задач/библиотеки и методы их использования где работает динамический полиморфизм (виртуальное наследование)
Вот я как раз написал, что хочу избежать флуда об ууух! mature таких программерах/архитектах, юзающих удачно все технологии в нужном контексте . Вопрос был применительно к ООП языкам.

CS>Соответсвенно есть это все другое где статический полиморфизм (templates, everything is a abstract typename) "играет всеми гранями".

CS>Есть еще функциональный подход — everything is a handle (HWND, HDC, void*, etc.)
По мне так everything is a handle/pointer не шибко отличается от "Все есть объект". Никакого versus. Просто соображения эффективности на уровне ядра или под 80486 .

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

Да да да. +20 баллов тебе .

CS>Да, есть System.Windows.Forms.Control, а есть также HWND.

CS>Да, есть System.IO.Stream, а есть FILE*...
CS>Ну давайте поспорим что лучше...
Я вапче говорил не об этом. Примем за аксиому, что все технологии полезны, и успокоимся. Я скорее имел в виду это
Автор: Rumata
Дата: 03.01.05
, это
Автор:
Дата: 21.12.04
или даже это
Автор: borisman2
Дата: 01.10.04
.
Re[3]: True OOP
От: c-smile Канада http://terrainformatica.com
Дата: 16.01.05 21:29
Оценка:
Здравствуйте, Poudy, Вы писали:

P>Я вапче говорил не об этом. Примем за аксиому, что все технологии полезны, и успокоимся. Я скорее имел в виду это
Автор: Rumata
Дата: 03.01.05
, это
Автор:
Дата: 21.12.04
или даже это
Автор: borisman2
Дата: 01.10.04
.


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

Это как раз понятно и имеет смысл обсуждать.

А то "Девочка, а девочка, ты кого больше любишь — папу или маму?" ...
"центральный класс или прослойку?"...

Всякий раз как слышу нечто типа "А ты какую руку больше любишь — левую или правую?" у меня закрадываются очень нехорошие подозрения...
Re[4]: True OOP
От: Poudy Россия  
Дата: 16.01.05 21:48
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Ага! Теперь ближе к делу: т.е. не "Каждый проблемный домен должен содержать свой центральный класс...",

CS>а вполне конкретные задачи и случаи.
Ну конечно конкретные ! А то! Хых. .
Я выдвинул.... так скааать... рекомендацию. В форме принципа. Рекомендацию новичкам и заблудшим душам при проектировании запутанных иерархий. Необязательную. Так правильно?
Re: True OOP
От: Gaperton http://gaperton.livejournal.com
Дата: 16.01.05 22:03
Оценка:
Здравствуйте, Poudy, Вы писали:

P>В свою очередь для ОО-библиотек есть похожие несуразности, которые я отношу к звеньям той же цепи:

P>1. Библиотека не последовательна в функциональности классов. Пример: в System.Windows.Forms.MenuItem нет Tag, а в std::string нет toUpper/toLower.
Вообще-то в std::string нет toUpper/toLower совсем не потому, что кто-то забый ее туда добавить. Предполагается что ты воспользуешься стандартным алгоритмом transform и соответствующей функцией. И сделано так не случайно. В этом проявляется другой принцип проектирования, противоположный тому, который ты предлагаешь. Жизнь непростая штука
Re[2]: : True OOP
От: Poudy Россия  
Дата: 16.01.05 22:26
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Вообще-то в std::string нет toUpper/toLower совсем не потому, что кто-то забый ее туда добавить. Предполагается что ты воспользуешься стандартным алгоритмом transform и соответствующей функцией. И сделано так не случайно. В этом проявляется другой принцип проектирования, противоположный тому, который ты предлагаешь. Жизнь непростая штука


Хороший принцип? Если ты о том же, о чем говорил McSeem2, то это всего лишь вариант реализации, а не принцип. В .Net есть ToUpper потому, что все строки в юникоде. А трансляция производится при помощи Encoding. И это правильнее, чем переводить translate'ом строку из неизвестной кодировки. А если в строку зашить указатель на кодировку, то опять нет проблем сделать ToUpper. Я сильно не прав?

Мне кажется просто, что STL и прочее писалось в бородатые года и как только появлялась необходимость в расширяемости народ качало из шаблонов в процедуры и назад, вместо использования стратегий и других паттернов. А почему? А потому что нет сборки мусора и вообще проблема с объектами (то он в куче, то в стеке). Я не спорю, что для C++ всё это верно. Я говорю, что это особенности реализации, а не принцип.
Re[4]: [3]: : Re[2]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 08:25
Оценка:
Забавно, как это ты сразу распознал во мне оппонента, и уже не видишь, что же я говорю.

Здравствуйте, Павел Кузнецов, Вы писали:

>> В .Net есть ToUpper потому, что все строки в юникоде. А трансляция производится при помощи Encoding. И это правильнее, чем переводить translate'ом строку из неизвестной кодировки. А если в строку зашить указатель на кодировку, то опять нет проблем сделать ToUpper. Я сильно не прав?


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


Так я и словом же не обмолвился, что translate делает всё сам. Я только сказал, что строка в std:: не хранит кодировки, и видимо это не позволило реализовать ToUpper сразу как штатную функцию, хоть бы само преобразование и задавалось где-то пользователем.

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


ПК>Тебе кажется неправильно. Стандартная библиотека C++ вообще и STL в частности изобилует примерами различных паттернов проектирования. Например, применительно к std::translate, можно легко распознать Iterator и (сюрприз?) Strategy.


Опять же, я даже не намекнул, что Алекс Степанов ничего не понимал в паттернах. Но реализовывал он их на шаблонах и процедурах (ну функторах). Оно для C++ неплохо, вероятно. Производительность, там, то да сё. Но работать с такой реализацией слегка, пусть на 0.01%, менее удобно, чем с "полнофункциональными" объектами. Вот такими 0.01% в тысяче мест .Net и переманивает сейчас программистов определенных задач, где поначалу господствовал практически один C++. И продолжает в том же духе
Автор: ZveN
Дата: 12.01.05
.
Re[2]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 09:03
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Вот в том-то и недостаток идеи наследования. После того, как иерархия создана, нет ни малейшей возможности проявить хоть какую-то гибкость. Взять ту же MFC. Есть класс CDC, у которого есть потомки, типа CClientDC и др. В нем так же есть функция PolyPolygon, которую я хочу заменить своей (более правильной, быстрой, причина на важна). Так каким образом не трогая исходников, я могу включить свой класс (с этой переопределенной функцией) в иерархию между CDC и CClientDC? Никаким! Таким образом, библиотека любой сложности, основанная на принципах иерерхий классов, является абсолютно черным ящиком и использовать ее можно лишь одним единственным способом: "щелкни кобылу в нос — она махнет хвостом".


Выходит, по твоему TRUE OOP — это язык без статического наследования? Или Python?
Re[8]: Согласен
От: Poudy Россия  
Дата: 17.01.05 13:28
Оценка:
Но всё-таки я хотел обсудить детали реализации на C++/C#/Java.
Выработать совет при построении иерархий в этих языках, считая что template'ов как бы нет в природе.
Re[9]: : Re[4]: [3]: : Re[2]: : True OOP
От: _vovin http://www.pragmatic-architect.com
Дата: 17.01.05 13:59
Оценка:
Gaperton wrote:

> _>Тут Степанов перебарщивает.

> _>Такое ощущение, что ООП он значет только по Java.
> Тут не в ООП дело . А в том, что функция max должна обладать параметрическим полиморфизмом по обоим аргументам. И всего-то.

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

> Степанов под "ООП" очевидно имеет в виду обыкновенные статически типизированные ОО языки, в которых полиморфизм обеспечивается посредством (только) классов.


Он вдобавок еще утверждает, что ООП началось с классов.

>

> _>Например, вот реализация max в Smalltalk:
> _>
> _>Magnitude>>max: operand
> _>    ^self < operand
> _>        ifTrue:  [operand]
> _>        ifFalse: [self]
> _>

>
> В смоллтоке ты используешь для этого базовый класс, как принято в ООП (первый аргумент — неявный), а тип второго аргумента тебя не волнует, так как язык динамически типизирован. Само разрешится.
>
> Что характерно, в любом не ОО динамически типизированном языке это будет записано еще проще, что-нибудь в духе
>
> max( a, b )
> {
>    return a < b ? b : a;
> }
>

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

Не совсем так, этот пример не распространяется на более сложные случаи.
В Smalltalk полиморфизм параметризован типом получателя (т.е. первого
параметра), а в твоем примере тип первого параметра статически
неопределим. Поэтому там нельзя применить double-dispatching для
сведения к полиморфизму по единственному параметру.

>

> В том же лиспе для max нет никакой необходимости использовать CLOS (как у тебя в примере) — можно просто функцию определить, работать будет также . Это у вас в смоллтоке другого выхода нет, как городить классы .

Наезд был на ООП и невозможность реализовать max в классах. Поэтому я
сказал слово CLOS.
Posted via RSDN NNTP Server 1.9
Re[10]: : Re[4]: [3]: : Re[2]: : True OOP
От: Gaperton http://gaperton.livejournal.com
Дата: 17.01.05 14:10
Оценка:
>> Что характерно, в любом не ОО динамически типизированном языке это будет записано еще проще, что-нибудь в духе
>>
>> max( a, b )
>> {
>>    return a < b ? b : a;
>> }
>>

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

_>Не совсем так, этот пример не распространяется на более сложные случаи.

_>В Smalltalk полиморфизм параметризован типом получателя (т.е. первого
_>параметра), а в твоем примере тип первого параметра статически
_>неопределим. Поэтому там нельзя применить double-dispatching для
_>сведения к полиморфизму по единственному параметру.
Неправда. Здесь все зависит только от того, как определен <. А все остальное — не имеет значения, так как в самой max ничего диспатчить не надо.
Re[11]: : Re[4]: [3]: : Re[2]: : True OOP
От: _vovin http://www.pragmatic-architect.com
Дата: 17.01.05 14:14
Оценка:
Gaperton wrote:

>>>Что характерно, в любом не ОО динамически типизированном языке это будет записано еще проще, что-нибудь в духе

>>>
>>>max( a, b )
>>>{
>>>   return a < b ? b : a;
>>>}
>>>

>>>абсолютно тот же эффект, только нет необходимости морочиться с базовыми классами — параметрический полиморфизм в динамически типизированных языках достигается без использования всяких классов.
>
>
> _>Не совсем так, этот пример не распространяется на более сложные случаи.
> _>В Smalltalk полиморфизм параметризован типом получателя (т.е. первого
> _>параметра), а в твоем примере тип первого параметра статически
> _>неопределим. Поэтому там нельзя применить double-dispatching для
> _>сведения к полиморфизму по единственному параметру.
> Неправда. Здесь все зависит только от того, как определен <. А все остальное — не имеет значения, так как в самой max ничего диспатчить не надо.

Хорошо, если < реализован средой для всех типов. Но если нужно добавить
Complex, то все, без автоматической диспетчеризации никуда.
Posted via RSDN NNTP Server 1.9
Re[9]: : Re[4]: [3]: : Re[2]: : True OOP
От: Трурль  
Дата: 17.01.05 14:33
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Тут не в ООП дело . А в том, что функция max должна обладать параметрическим полиморфизмом по обоим аргументам. И всего-то.

Дело в том, что функция max может обладать параметрическим полиморфизмом по трем аргументам, а по двум.
Re[4]: : True OOP
От: Cyberax Марс  
Дата: 17.01.05 14:36
Оценка:
Gaperton пишет:

> Дизайн, сделаный этому принципу, обладает рядом очевидных практических

> преимуществ. translate c toupper (которая, кстати, может тоже быть
> полиморфной, и работать корректно как на unicode символах, так и на
> обычных) отработает корректно не только на строке, но и *вообще на
> любом контейнере*, где лежат символы. Принцип замечательный — у тебя
> возможностей комбинировать функционал больше на порядок. Ты можешь
> добавить свою реализацию хитрых строк в отдельном классе, и получишь
> для нее toupper автоматически. Не заморачиваясь организацией иерархии
> наследования.

Да, причем если я в STL захочу сделать toUpper/toLower для эльфийского
языка, транскрибированного арабскими буквами, то мне просто нужно будет
сделать специальный функтор, и я смогу сохранить consistent интерфейс. А
вот в .NET — никак.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[5]: [3]: : Re[2]: : True OOP
От: Павел Кузнецов  
Дата: 17.01.05 14:52
Оценка:
Poudy,

> уже не видишь, что же я говорю.


Я старался. Коль не получилось — сожалею.

> Я только сказал, что строка в std:: не хранит кодировки, и видимо это не позволило реализовать ToUpper сразу как штатную функцию, хоть бы само преобразование и задавалось где-то пользователем.


Если бы возникло желание, можно было бы поместить соответствующие функции, например, в char_traits, аргумент std::basic_string. У такого способа есть и достоинства, и недостатки: с одной стороны, в compile-time будут осуществляться проверки на совпадение кодировки при строковых операциях, что очень хорошее дело; с другой, все вспомогательные функции придется делать шаблонами и т.п.

Вне зависимости от реализации снабжения строки информацией о кодировке (помещение функций в char_traits, помещение дополнительного указателя в std::string и т.п.), проблема остается той же: функций, зависящих от кодировки и locale, много, а std::string и без того уже явно перегруженный класс. Имхо, намного больше пользы было бы не в расширении существующего класса, а в выносе из него ряда вспомогательных алгоритмов типа find_last_not_of и т.п.

В общем, есть ощущение, что в std::string не потому нет ToUpper, что там нет информации о кодировке, а там нет информации о кодировке потому, что решили туда не помещать еще множество функций, в т.ч. и ToUpper.

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


> ПК> Тебе кажется неправильно. Стандартная библиотека C++ вообще и STL в частности изобилует примерами различных паттернов проектирования. Например, применительно к std::translate, можно легко распознать Iterator и (сюрприз?) Strategy.


> Опять же, я даже не намекнул, что Алекс Степанов ничего не понимал в паттернах.


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

> Но реализовывал он их на шаблонах и процедурах (ну функторах). Оно для C++ неплохо, вероятно. Производительность, там, то да сё.


Дык, помимо производительности есть и еще другие приятности: возможность использовать предоставленные алгоритмы для своих контейнеров и последовательностей, а иногда и при использовании сторонних библиотек без вмешательства в последние; возможность для готовых (стандартных, и сторонних) контейнеров использовать свои алгоритмы.

> Но работать с такой реализацией слегка, пусть на 0.01%, менее удобно, чем с "полнофункциональными" объектами.


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

Скорее у меня есть обратные примеры, когда ребята мучаются, пытаясь написать "обобщенные" переходники к ряду алгоритмов-методов на C#. Я это вижу у себя на работе, да и в Инете следы легко находятся:
http://www.wintellect.com/powercollections
http://codeproject.com/csharp/cs_functors.asp
И в C++/CLI, вне зависимости от легкого доступа к коллекциям .Net, решили делать STL.Net, что тоже должно наталкивать на определенные мысли...
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[7]: : Re[4]: [3]: : Re[2]: : True OOP
От: Павел Кузнецов  
Дата: 17.01.05 15:01
Оценка:
Poudy,

> Он тут явно использует семантическую подмену "Inheritance and interfaces don't help" на "Inheritance and interfaces are useless".


Речь-то идет не о чем-то отвлеченном, а о конкретных задачах: контейнеры, алгоритмы, и их сопряжение. В этом случае inheritance and interfaces don't work.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[10]: Согласен
От: Poudy Россия  
Дата: 17.01.05 15:06
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>В Java шаблоны заменяются на интерфейсы, абстрактные алгоритмы работают

C>уже через эти интерфейсы. Сами алгоритмы реализуются в static-методах
C>классов. Смотри java.util.Collections (методы сортировки, например).
Ты как не читал рут данной темы, чесслово .
Re[8]: : Re[4]: [3]: : Re[2]: : True OOP
От: Cyberax Марс  
Дата: 17.01.05 15:11
Оценка:
Павел Кузнецов пишет:

>> Он тут явно использует семантическую подмену "Inheritance and

> interfaces don't help" на "Inheritance and interfaces are useless".
> Речь-то идет не о чем-то отвлеченном, а о конкретных задачах:
> контейнеры, алгоритмы, и их сопряжение. *В этом* случае inheritance
> and interfaces don't work.

Но-но! Inheritance — действительно нафиг не нужна, а вот интерфейсы —
вполе себе подходят. Смотри java.util.Collections...

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[5]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 15:37
Оценка:
C>Gaperton пишет:

>> Дизайн, сделаный этому принципу, обладает рядом очевидных практических

>> преимуществ. translate c toupper (которая, кстати, может тоже быть
>> полиморфной, и работать корректно как на unicode символах, так и на
>> обычных) отработает корректно не только на строке, но и *вообще на
>> любом контейнере*, где лежат символы. Принцип замечательный — у тебя
>> возможностей комбинировать функционал больше на порядок. Ты можешь
>> добавить свою реализацию хитрых строк в отдельном классе, и получишь
>> для нее toupper автоматически. Не заморачиваясь организацией иерархии
>> наследования.


C>Cyberax пишет:

C>Да, причем если я в STL захочу сделать toUpper/toLower для эльфийского
C>языка, транскрибированного арабскими буквами, то мне просто нужно будет
C>сделать специальный функтор, и я смогу сохранить consistent интерфейс. А
C>вот в .NET — никак.

Хитрые строки и эльфийские языки — не наш метод . Шутка.

Всё то же самое можно сделать на интерфейсах. Вопрос только в количестве кода и производительности. Так что тут нет никаких ограничений для ООП.

Насчет хорошего дизайна я не соглашусь, постольку такая реализация преобразований может приводить к runtime ошибкам. Как я уже говорил, можно перекодить строку не в той кодировке. Если бы это было XML tree, которое обрабатывается строителем шут знает во что, всё понятно. Но строки? Этож стандартная всем известная весчь! Уж в них-то можно завиксировать некоторые вещи явно. Пусть оно будет точно так же спроектировано и расширяемо, я не против. Но ведь хорошо же, что не приходится писать каждый раз basic_string<char>. Ведь правильно же?
Re[6]: : True OOP
От: Gaperton http://gaperton.livejournal.com
Дата: 17.01.05 16:02
Оценка:
Здравствуйте, Poudy, Вы писали:

P>Всё то же самое можно сделать на интерфейсах. Вопрос только в количестве кода и производительности. Так что тут нет никаких ограничений для ООП.


P>Насчет хорошего дизайна я не соглашусь, постольку такая реализация преобразований может приводить к runtime ошибкам.

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

Кстати, runtime ошибки у вас будут так или иначе, и на практике такой дизайн их количества серьезно не увеличит (он увеличивает степень и простоту повторного использования кода, что уменьшит общее количество кода). Накосячишь в другом месте — какая разница .

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

А вот в случае использования шаблонов (С++), параметрических типов (OCaml, Haskell, Clean, и прочее основанное на хиндли-милнере, плюс для экзотики CLU), и, вероятно, generics (Java, C#) — нет. Такая ошибка будет гарантированно выловлена при компиляции.
Re[7]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 16:14
Оценка:
Здравствуйте, Gaperton, Вы писали:

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

G>А вот в случае использования шаблонов (С++), параметрических типов (OCaml, Haskell, Clean, и прочее основанное на хиндли-милнере, плюс для экзотики CLU), и, вероятно, generics (Java, C#) — нет. Такая ошибка будет гарантированно выловлена при компиляции.
Это как? Если и строка из w_char, к примеру, то чем помогут шаблоны и дженерики?
Re[8]: : True OOP
От: Gaperton http://gaperton.livejournal.com
Дата: 17.01.05 16:39
Оценка:
Здравствуйте, Poudy, Вы писали:

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


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

G>>А вот в случае использования шаблонов (С++), параметрических типов (OCaml, Haskell, Clean, и прочее основанное на хиндли-милнере, плюс для экзотики CLU), и, вероятно, generics (Java, C#) — нет. Такая ошибка будет гарантированно выловлена при компиляции.
P>Это как? Если и строка из w_char, к примеру, то чем помогут шаблоны и дженерики?
Если ты передал трансформу туаппер, который принимает аргументом char, должна быть ошибка типизации. Там, у нея внутре, при попытке инстанциации шаблона, когда не сойдется тип элемента контейнера и сингнатура переданной функции.
Re[9]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 17:50
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Если ты передал трансформу туаппер, который принимает аргументом char, должна быть ошибка типизации. Там, у нея внутре, при попытке инстанциации шаблона, когда не сойдется тип элемента контейнера и сингнатура переданной функции.

Так мы о кодировках или о невозмодности передать туда float? кодировки не исчерпываются количеством байт. а typedef win1251_char char по-моему не поможет и шаблон схавает такую букву как char всё равно.
Re[10]: : True OOP
От: Gaperton http://gaperton.livejournal.com
Дата: 17.01.05 18:00
Оценка:
Здравствуйте, Poudy, Вы писали:

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


G>>Если ты передал трансформу туаппер, который принимает аргументом char, должна быть ошибка типизации. Там, у нея внутре, при попытке инстанциации шаблона, когда не сойдется тип элемента контейнера и сингнатура переданной функции.

P>Так мы о кодировках или о невозмодности передать туда float? кодировки не исчерпываются количеством байт. а typedef win1251_char char по-моему не поможет и шаблон схавает такую букву как char всё равно.
Мы о unicode, как я думал . А если о кодировках, и делать как ты говоришь — то да, схавает.

Но, эта, все в твоих руках, значить! class win1251_char , раз пошла такая пьянка. Так даже удобнее — сможешь весьма красиво ввести поддержку преобразований из одной кодировки в другую.
Re[4]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 18:10
Оценка:
Здравствуйте, McSeem2, Вы писали:

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


P>>Мне кажется просто, что STL и прочее писалось в бородатые года и как только появлялась необходимость в расширяемости народ качало из шаблонов в процедуры и назад, вместо использования стратегий и других паттернов. А почему? А потому что нет сборки мусора и вообще проблема с объектами (то он в куче, то в стеке).

MS>Так. Пожалуйста, официант, мухи — отдельно, котлеты — отдельно.
Ага, только тут ты и клиент, официант, и бармен, и муха в одном лице.

P>>Я не спорю, что для C++ всё это верно. Я говорю, что это особенности реализации, а не принцип.


MS>Это именно принцип. Не знаю, сумею ли донести свою мысль, она у меня самого живет лишь на уровне интуиции. Эта мысль очень созвучна с принципом бритвы Оккама, "не плодите сущностей сверх необходимости". Иначе говоря, не надо решать неуместных задач. Однако в жизни не все так просто — всегда нужен компромис и разумный баланс. Поясню на примере той же toUpper. Во времена разработки STL было ясно, что в мире существует не только Английский алфавит и не только 7-битовая ASCII кодировка, следовательно толку от toUpper будет мало (для простоты мы не принимаем в расчет locale, ctype, etc).

Резонный вопрос: если бы в строке был экземпляр Encoding. Шаблонированый и т.д. Это что-нибудь испортило бы? Или у нас хоть когда-нибудь возникает необходимость тупого побайтного копирования строки из китайского в русский?

MS>Нужен некий обобщенный механизм, позволяющий — приложив малую толику усилий — достичь нужного результата. Я не утверждаю, что это хорошо, я лишь утверждаю, что в STL именно такой принцип и используется. Это имеет и преимущества и недостатки. Главное преимущество — когда появился Unicode, в STL не оказалось ничего, противоречящего этой новой сущности. Иними словами, STL успешно пережил нашествие Unicode.

Байты тоже пережили юникод. И молотки пережили юникод. Потому что в них никогда не было толковой поддержки ни одной кодировки .

MS>Главный же недостаток — именно в чрезмерной обобщенности, а именно в том, что все-таки необходимо приложить некие усилия для достижения результата.

Да да. Как с ассемблером примерно. Бери регистры и делай с ними што хошь.

MS>Но Unicode сам по себе — это тоже ограничение, например, только Китай за всю историю своего существования накопил более 64K иероглифоф (кстати, что будет означать toUpper применительно к Китайскому языку?).

ToUpper() применительно к китайскому ничего не будет И ничего страшного.

MS>В то время, как в STL вполне можно реализовать строки на основе 24-битовых символов (если 32 покажется слишком дорого). Далее, кроме естественных алфавитов, в мире полно искусственных, например, ACTG (нуклеотиды) — всего-навсего 4 буквы, 2 бита на символ. Для него операция toUpper — вообще неуместна. Таким образом, строки в STL обладают значительно большей общностью и более широким спектром решаемых задач.

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

MS>Но с другой стороны, Unicode вполне удовлетворяет требованиям в 99% случаев. Грубо говоря (утрированно), с использованием Unicode остается лишь 1% нерешаемых задач, а с использованием STL — можно решить 99.9% задач, следовательно, остается 0.1%.

При этом со сдвиговым регистром можно (при сааааавсем небольшой дополнительно затрате усилий) сделать всё то же самое. Зато насколько универсальнее!! Какое элегантное и быстрое решение!

MS>И здесь все зависит от того, с какого конца считать — можно сказать, что разница составляет всего-навсего 0.9%, а можно — что разница в 10 раз.

И я о том же. Неизвестно где теряются драгоценные нервы.

MS>Это я таким длинным образом пытаюсь вернуться к изначальному вопросу.

MS>

MS>Каждый проблемный домен должен содержать свой центральный класс, содержащий наиболее полную (а не наиболее непротиворечивую) для данного домена функциональность.

MS>Таким образом, все упирается в понятия. Что значит "наиболее непротиворечивая функциональность" — можно определить, описать и понять.
"А я вот нет. А я вот несогласен со всем, чтобы вы не подумали." Спорить о непротиворечивосте и полноте можно одинаково успешно.

MS>Метафорически можно сказать, что попытки описать функциональность наиболее полно — это попытки накормить весь мир рыбой, что является заведомо нереальным и бесперспективным ибо, когда у тебя кончится рыба, те же самые люди тебя и побъют. Гораздо более конструктивно — научить людей пользоваться удочками. Да, но при этом, люди конечно же сопротивляются — "не хочу удочку, хочу сразу рыбу". Здесь требуется определенное мужество — не поддаться соблазну и не сказать "на тебе рыбу, только отвяжись".

Спасибо за лирическое сравнение, но я почти не прослеживаю точной связи. Эта метафора привносит так много дополнительных, и не относящихся к нашей теме напрямую, аспектов (как то: воспитание, относительность знаний), что только вносит путаницу в умы.
Re[4]: : True OOP
От: WolfHound  
Дата: 17.01.05 18:22
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Да, как справедливо заметил AndrewVK, таким способом нельзя реализовать некоторые вещи.
Автор: AndrewVK
Дата: 06.01.05
Но ведь, если вдуматься, эти "вещи" как раз и являются следствием "зависания" на парадигме наследования. И причем, не просто "зависания", а использования идеи наследования неестественным образом — преобразованием от базового класса к производному (upcast или downcast — я их все время путаю, поскольку до сих пор не знаю, куда растет дерево наследования — вверх или вниз ). На мой взгляд, как только возникает необходимость в таком преобразовании, значит что-то здесь не так, и это является серьезной уликой попыток решать неуместные задачи.

Гм. Я хочу поговорить об этом...
Есть модель некоторого дерева ноды которого могут иметь разные типы. Например файловая система есть несколько типов нод: папка, текстовый фаил, графический фаил, архив... Папка, архив... имеют детей.
Допустим нам надо отобразить это дерево в пользовательском интерфейсе. Выглядить это должно так: с права дерево, а с лева отображение текущей ноды.
Как решать это с помощью наследования и даункастов понятно.
Имеем примерно такую иерархию
INode
INodeWithChildren : INode
IFolder : INodeWithChildren
IArchive : INodeWithChildren
ITextFile : INode
IGraphicFile : INode

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

Внимание вопрос: А как это сделать без наследования, определения конкретного типа и даункастов?
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 18:43
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Но, эта, все в твоих руках, значить! class win1251_char , раз пошла такая пьянка. Так даже удобнее — сможешь весьма красиво ввести поддержку преобразований из одной кодировки в другую.

Избави боже. Кодировок для этого слишком много.
Re[6]: : True OOP
От: Andy77 Ниоткуда  
Дата: 17.01.05 19:20
Оценка:
Здравствуйте, Poudy, Вы писали:

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


P>В данном случае, скорее всего, нужнен только один класс — Узел.


P>Нужно использовать "поле типа", которое бы возвращало "тип" данного узла в виде объекта Тип. Поскольку Тип является объектом, их может быть сколько угодно. В Типе задается всё, что нужно знать о типе.


P>Также можно использовать паттерн мост (Bridge), если логика поведения узла зависит от типа. Выполнение специфичных методов отдается на откуп другому объекту (этим объектом может быть тот же Тип).


P>В остальном же лучше нашпиговать класс Узла всеми часто используемыми и полезными методами и свойствами. Включая Preview(), IsImage, Extention, HaveExtention, IsReadOnly и т.д.


Бррр, получилась какая-то странноватая эмуляция полиморфизма — а зачем?
Re[7]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 19:50
Оценка:
Здравствуйте, Andy77, Вы писали:

A>Бррр, получилась какая-то странноватая эмуляция полиморфизма — а зачем?

Затем, что для удобства работы и емкости кода в Узел придется ввести методы, которые как бы "знают" о типе наследников. А это ересь по определению.

Как бы... в данном случае полиморфизм не нужен. Для чего, перегружать Name? Или возвращать иконку? Эмуляция полиморфизма, как ты говоришь, позволит лучше контролировать этот самый полиморфизм. То, что ты хочешь сделать тут полиморфно, не является прямой обязанностью объекта. Это скорее требования других систем к нему. Поэтому лучше бы их и реализовать отдельно. Ты же не делаешь так, чтобы класс и рисовал, и сериализовал, и приводил, и авторизовывал, и парсил, и вфводил в HTML и документировал все свои объекты сам.
Re[8]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 20:55
Оценка:
Захотелось написать еще одно обоснование.

Повторю, что в наследовании классов я вижу наследование интерфейса и повторное использование кода. При этом с идеальной точки зрения наследование желательно применять только тогда, когда это удовлетворяет [i]семантике иерархии. Т.е. когда каждый новый наследник отличается существенно большей функциональность, сложностью и специализацией. Заметим, что в построении GUI, где OOP парадигма очевидно преуспела, мы видим именно такие примеры иерархий и использования наследования.

Я не согласен с AndrewVK, что наследование классов (классов?) необходимо для полиморфизма. Для динамических языков без наследования вопрос полиморфизма вообще не стоит (как в JavaScript). Полиморфизма можно добиться одними интерфейсами. Возможно, он имел в виду другой полиморфизм — полиморфизм обобщенных алгоритмов, выражаемых в виде класса.

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

Кстати, в процессе поиска аргументов нарыл статью (и даже целый сайт).
Моей точки зрения она не аргументирует, но очень интересена по этому вопросу в целом: http://www.melikyan.com/dalshe/articles/oop.html.
Re[9]: : True OOP
От: prVovik Россия  
Дата: 17.01.05 21:11
Оценка:
Здравствуйте, Poudy, Вы писали:

P>Повторю, что в наследовании классов я вижу наследование интерфейса и повторное использование кода.


Вместо этого можно применять делегирование. И если еще автоматизировать этот процесс, то будет совсем хорошо.
... << RSDN@Home 1.1.4 @@subversion >>
лэт ми спик фром май харт
Re[10]: : True OOP
От: Poudy Россия  
Дата: 17.01.05 21:22
Оценка:
Здравствуйте, prVovik, Вы писали:

V>Вместо этого можно применять делегирование. И если еще автоматизировать этот процесс, то будет совсем хорошо.

А я говорю механизм!!! Ну скока можно... я же не говорил, что единственный механизм.
Re[9]: : True OOP
От: Зверёк Харьковский  
Дата: 17.01.05 21:43
Оценка:
Здравствуйте, Poudy, Вы писали:

P>Кстати, в процессе поиска аргументов нарыл статью (и даже целый сайт).

P>Моей точки зрения она не аргументирует, но очень интересена по этому вопросу в целом: http://www.melikyan.com/dalshe/articles/oop.html.
Сайт в целом , как и было сказано
Автор: Зверёк Харьковский
Дата: 10.12.04
.
А в частности эта статья . Точнее, лично мне — не глянулась
сам слушаю и вам рекомендую: Зимовье зверей — Мой голос мой голубь
FAQ — це мiй ай-кью!
Re[5]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 17.01.05 23:27
Оценка:
Здравствуйте, Poudy, Вы писали:

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


А программа с классами, но без наследования?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[5]: : True OOP
От: Костя Ещенко Россия  
Дата: 18.01.05 00:02
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Гм. Я хочу поговорить об этом...

WH>Есть модель некоторого дерева ноды которого могут иметь разные типы. Например файловая система есть несколько типов нод: папка, текстовый фаил, графический фаил, архив... Папка, архив... имеют детей.
WH>Допустим нам надо отобразить это дерево в пользовательском интерфейсе. Выглядить это должно так: с права дерево, а с лева отображение текущей ноды.
WH>Как решать это с помощью наследования и даункастов понятно.
WH>Имеем примерно такую иерархию
WH>
WH>INode
WH>INodeWithChildren : INode
WH>IFolder : INodeWithChildren
WH>IArchive : INodeWithChildren
WH>ITextFile : INode
WH>IGraphicFile : INode
WH>

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

WH>Внимание вопрос: А как это сделать без наследования, определения конкретного типа и даункастов?


На мой взгляд наиболее расширяемым (и при этом недорогим) решением является введение в INode функции а-ля QueryInterface. Отсюда следует что все-же придется ручками перечислять интерфейсы в реализации QueryInterface. Кроме того каждому интерфейсу в рантайме должен соответствовать некий идентификатор. Короче очень похоже на запрос интерфейса в COM.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[5]: : True OOP
От: Cyberax Марс  
Дата: 18.01.05 05:30
Оценка:
WolfHound пишет:

> Есть модель некоторого дерева ноды которого могут иметь разные типы.

> Например файловая система есть несколько типов нод: папка, текстовый
> фаил, графический фаил, архив... Папка, архив... имеют детей.
> Допустим нам надо отобразить это дерево в пользовательском интерфейсе.
> Выглядить это должно так: с права дерево, а с лева отображение текущей
> ноды.
> Как решать это с помощью наследования и даункастов понятно.
> Имеем примерно такую иерархию
>
>INode
>INodeWithChildren : INode
>IFolder : INodeWithChildren
>IArchive : INodeWithChildren
>ITextFile : INode
>IGraphicFile : INode
>
>
> Через INodeWithChildren можно получить список детей
> Далие при построение дерева смотрим является ли очередная нода
> INodeWithChildren если да то рекурсивно запрашиваем потомков...
> Далие когда пользователь выберает конкретную ноду определяем ее тип и
> отображаем ее соответствующим образом.
> Вставлять в модель информацию о виде не логично ибо видов может быть
> сколько угодно.
> Внимание вопрос: А как это сделать без наследования, определения
> конкретного типа и даункастов?

Как раз только что такое же написал, только статически. У меня есть свой
собственный движок для запросов на моем SQL-подобном языке, есть парсер,
который строит синтаксическое дерево запроса. Имеем:
======================
typedef boost::variant<
restriction_and,
restriction_compareprops,
...
restriction_subrestriction> restriction_t;

struct restriction_and : public restriction_base_t, public
nonleaf_node<restriction_and>
{
restriction_vector_t children;

size_t getChildrenNum() const;
const restriction_t& getChild(size_t num) const;
};

struct restriction_compareprops : public restriction_base_t
{
mapitag_t left,right;
boost::value_initialized<relation_op> operation;
};
...
======================

Рекурсия по дереву делается так:
=========================
class mql_print_visitor
: public boost::static_visitor<>
{
public:
std::ostream &stream;

mql_print_visitor(std::ostream &stream);
template<class T>
void operator()(const nonleaf_node<T> &node);
...
void operator()(const restriction_compareprops &restr);
};

...
std::stringstream str;
mql_print_visitor printer(str);
boost::apply_visitor(printer,restriction); //'restriction' is an
instance of restriction_t
=========================

В плюсах: используются только статические объекты, boost::variant
предоставляет мне "на халяву" операторы сравнения, присваивания и вывода
в поток.

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

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[6]: : True OOP
От: WolfHound  
Дата: 18.01.05 08:42
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

КЕ>На мой взгляд наиболее расширяемым (и при этом недорогим) решением является введение в INode функции а-ля QueryInterface. Отсюда следует что все-же придется ручками перечислять интерфейсы в реализации QueryInterface. Кроме того каждому интерфейсу в рантайме должен соответствовать некий идентификатор. Короче очень похоже на запрос интерфейса в COM.

Я сейчас пишу под .NET со всеми вытекающими...
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: : True OOP
От: WolfHound  
Дата: 18.01.05 08:42
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Если вопрос не праздный,

Ну не то чтобюы совсем празный... в принципе я только подобную иерархию изобразил. Полет нормальный...
ПК>то полагаю, что тебе может показаться очень интересной книга: John Vlissides. Pattern Hatching: Design Patterns Applied (Джон Влиссидес. Применение шаблонов проектирования. Дополнительные штрихи) — заметную часть книги занимает анализ как раз аналогичного случая.
Нет у меня этой книги.
ПК>Краткий вывод такой: в данной ситуации оправдано использование "жирных" интерфейсов.
А можно чуть мение краткий? Ибо у меня есть сомнения в оправдоности жирных интерфейсов.

ЗЫ Я привел выдуманую иерархию. В моем случае элементы дерева очень сильно различаются. Общие у них только то что они являются элементами одного и тогоже дерева. И только некоторые из них могут иметь детей при том вполне определенных типов.
ЗЗЫ Отображения элементов не имеют между собой ни чего общего.
ЗЗЗЫ В моем случае интерфейс получится ооочень толстым. А самое главное я не вижу ни одного плюса.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: : True OOP
От: WolfHound  
Дата: 18.01.05 08:42
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Ты будешь мощно смеяться — не знаю как. И никто толком не знает.

Вот и я о томже...
MS>Рискну модифицировать и продолжить иерархию.
Вот не надо модифицировать иерархию. Я тоже не дурак и прекрасно знаю чем грозит такое "модифицирование" (тут болие уместно извращение) иерархии...
Я использую лишь наследование интерфейсов. (*) Наследование реализации в данной иерархии спользовано лишь для INode и INodeWithChildren
Общие вещи для остальных классов реализваны через агрегацию.(в С++ я бы использовал приватное наследование в прочем это детали)

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

Рассамтриваю динамический случай.
1)Можно случайно подцепить объект у которого просто подошол набор методов что ИМХО не есть гуд.
2)Можно случайно опечататся и потом долго искать а кокого не подцепляется нужный объект
3)Эффективно реализовать очень сложно.(если вобще возможно)
MS>У нас есть одна единственная сущность — нода.
У меня есть две сущьности "нода" и "нода с детьми" в принципе их можно объеденить но я счел что болие умесно будет их разделить для улучшение диагностики ошибок.(и как бесплатный бонус некоторое уменьшение издержек)
MS>Мы берем эту ноду и пытаемся "примерять" разные интерфейсы, существующие независимо от имплементации. Ну, примерно, как в Хероне.
Не уверен что это всегда оправдано.
MS>Вот еще-бы как-то это сделать совсем динамически...
Во во...

(*)Эта иерархия не 1 в 1 то что я сейчас делаю но некоторое представление о структуре дает.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: : True OOP
От: Poudy Россия  
Дата: 18.01.05 08:51
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>ЗЫ Я привел выдуманую иерархию. В моем случае элементы дерева очень сильно различаются. Общие у них только то что они являются элементами одного и тогоже дерева. И только некоторые из них могут иметь детей при том вполне определенных типов.

Зачем ты вообще сделал их элементами дерева? IMHO, если "состоять в дереве" не является их прямой функцией, то дерево нужно сделать отдельно от этих типов. Хранить объект в Tag или чем там еще узла дерева и синхронизить структуру дерева с объектами когда надо. Дерево строишь билдером, синхронизируешь состояние листенерами. Грамотное и гибкое решение.

WH>ЗЗЫ Отображения элементов не имеют между собой ни чего общего.

Тем более.

WH>ЗЗЗЫ В моем случае интерфейс получится ооочень толстым. А самое главное я не вижу ни одного плюса.

Толще, чем у Control? Сомневаааюсь.
Re[8]: : True OOP
От: WolfHound  
Дата: 18.01.05 10:07
Оценка:
Здравствуйте, Cyberax, Вы писали:

>> Я использую лишь наследование интерфейсов. (*) Наследование реализации

>> в данной иерархии спользовано лишь для INode и INodeWithChildren
C>Ну так и это нафиг убери. У тебя же интерфейсы, зачем делать
C>INodeWithChildren? Сделай интерфейс IChildrenContainer.
Гм. Тоже вариант. Спасибо я подумаю.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.01.05 10:56
Оценка:
Здравствуйте, McSeem2, Вы писали:

AVK>> 1) В моем примере преобразования от базового к производному не было


MS>Упрек безусловно справедливый, если придерживаться рамок C# или Java. Но наследование интерфейсов — все равно остается наследованием.


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

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


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

MS> Ну, примерно, как в Хероне.


А как в Хероне я так однозначно и не понял. Ты с ПК говорите что там чистая статика, а при попытке полиморфизма компилятор ругается, c-smile говорит о некоей прозрачной механике подстановки полиморфизма когда нужно, но как это работает так и не сказал (я услышал только про какие то таблицы, которые строит компилятор, но их потенциальный размер навевает сомнения).
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[6]: : True OOP
От: LCR Россия lj://_lcr_
Дата: 18.01.05 11:01
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

КЕ>На мой взгляд наиболее расширяемым (и при этом недорогим) решением является введение в INode функции а-ля QueryInterface. Отсюда следует что все-же придется ручками перечислять интерфейсы в реализации QueryInterface. Кроме того каждому интерфейсу в рантайме должен соответствовать некий идентификатор. Короче очень похоже на запрос интерфейса в COM.


Одна из проблем COM — это то что от любого интерфейса нужно уметь шагнуть к любому другому интерфейсу, при этом объект остаётся как-бы "за кулисами" и к нему доступа нет. Отсюда известные грабли с наследованием реализаций.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[6]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.01.05 11:06
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

КЕ>На мой взгляд наиболее расширяемым (и при этом недорогим) решением является введение в INode функции а-ля QueryInterface. Отсюда следует что все-же придется ручками перечислять интерфейсы в реализации QueryInterface. Кроме того каждому интерфейсу в рантайме должен соответствовать некий идентификатор.


Фактически полное дублирование рефлекшена. И что это даст?
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[6]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.01.05 11:06
Оценка:
Здравствуйте, Cyberax, Вы писали:

1) Цитировать нужно только то что необходимо.
2) Код надо заключать в соответствующие теги.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[10]: : True OOP
От: Poudy Россия  
Дата: 18.01.05 11:43
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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

Всё так

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

AVK>Не только. Наследование (в статически типизируемых языках) это как минимум две вещи — наследование интерфейса и наследование реализации. Главная хитрость — уметь применять оба аспекта таким образом, чтобы не возникало описанных нехороших эффектов.
Я писал выше о наследовании интерфейса, и имел здесь в виду, что при условии наличия наследования интерфейса вроде как во всех приличных языках, в спорах можно рассматривать только эффект повторного использования кода.
Re[11]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.01.05 12:28
Оценка:
Здравствуйте, Poudy, Вы писали:

P>Я писал выше о наследовании интерфейса,


Я, честно говоря, этого момента не уловил. Твой резюм:

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

косвенно намекает именно на комбинированное наследование — интерфейса и реализации. Поскольку если мы говорим о наследовании интерфейса только то, как правило, никакого единого центрального интерфейса не существует и уж точно ни о какой содержащейся функциональности речи вобще идти не может.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[12]: : True OOP
От: Poudy Россия  
Дата: 18.01.05 12:42
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Я, честно говоря, этого момента не уловил. Твой резюм:

AVK>

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

AVK>косвенно намекает именно на комбинированное наследование — интерфейса и реализации. Поскольку если мы говорим о наследовании интерфейса только то, как правило, никакого единого центрального интерфейса не существует и уж точно ни о какой содержащейся функциональности речи вобще идти не может.
Да, всё так. Наследование реализации я и имел в виду.

Также я считаю, что перепрыгивание с дерева классов на дерево интерфейсов проблемы не решает. Дело ведь не в полиморфном коде, а в громоздкости иерархии и кастах, IMHO.
Re[13]: : True OOP
От: Poudy Россия  
Дата: 18.01.05 12:50
Оценка:
Здравствуйте, Poudy, Вы писали:

P>Да, всё так. Наследование реализации я и имел в виду.

Тьфу, коряво как-то выразился .

Имел в виду, что в

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

речь идет о комбинированном наследовании. Таким образом я пытаюсь громоздкую интерфейсную иерархию свести к более простой и короткой, переложив больше обязанностей на реализацию рутового интерфейса в рутовом классе. При этом вопросы полиморфности хорошо решаются делегированием и в целов классов и интерфейсов получается меньше.
Re[13]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.01.05 13:00
Оценка:
Здравствуйте, Poudy, Вы писали:

P>Также я считаю, что перепрыгивание с дерева классов на дерево интерфейсов проблемы не решает.


Ну если 1 в 1 копировать то не решает. Вот только из интерфейсов как правило полноценное дерево никто не делает. Как я уже писал — наследование в этом случае используется исключительно в качестве констрейнта.

P> Дело ведь не в полиморфном коде, а в громоздкости иерархии и кастах, IMHO.


Дай дураку в руки ... Ну ты понял
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[7]: : True OOP
От: Павел Кузнецов  
Дата: 18.01.05 14:22
Оценка:
AndrewVK,

> А как в Хероне я так однозначно и не понял. Ты с ПК говорите что там чистая статика, а при попытке полиморфизма компилятор ругается, c-smile говорит о некоей прозрачной механике подстановки полиморфизма когда нужно, но как это работает так и не сказал (я услышал только про какие то таблицы, которые строит компилятор, но их потенциальный размер навевает сомнения).


В случае интерфейсов:

1) Для классов — чистая статика.
2) Для интерфейсов — обычный run-time полиморфизм.
3) Ссылку на объект класса можно привести к ссылке на интерфейс ("прозрачная механика подстановки полиморфизма, когда нужно").
4) В точке приведения компилятору становится известно о том, что для данного класса нужно построить VMT, подходящую для данного интерфейса.
5) Интерфейс = указатель на объект + указатель на VMT.

Соответственно, таблиц виртуальных функций будет не больше, чем в случае наследования от интерфейсов, и количество нужных таблиц транслятору известно заранее, в статике.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[8]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.01.05 14:32
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>4) В точке приведения компилятору становится известно о том, что для данного класса нужно построить VMT, подходящую для данного интерфейса.


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

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


Я уже на пальцах доказал что если у нас приведение чисто статическое то полиморфизм невозможен. Повторять всю эту бодягу по новой нет никакого желания. Кому интересно тот все уже давно понял.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[9]: : True OOP
От: Павел Кузнецов  
Дата: 18.01.05 14:39
Оценка:
AndrewVK,

> ПК>4) В точке приведения компилятору становится известно о том, что для данного класса нужно построить VMT, подходящую для данного интерфейса.


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


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

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


> Я уже на пальцах доказал что если у нас приведение чисто статическое то полиморфизм невозможен. Повторять всю эту бодягу по новой нет никакого желания. Кому интересно тот все уже давно понял.


Гм... Твой пример был совсем из другой вселенной: ну не будет никто так делать в подобном языке, не будет. Вместо этого работа будет идти с интерфейсами. Ты снова и снова говоришь о полиморфизме классов, вместо чего в данном языке должен использоваться полиморфизм интерфейсов.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[10]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.01.05 14:49
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

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


Вот только одна проблема — компоненты с такими интерфейсами не создашь. А язык, который не пригоден для КОП лично мне на настоящий момент просто не интересен.

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


Нет никакой ложки. Нет полиморфизма интерфейсов и классов, есть полиморфизм. А если в языке их исскуственно разрезали то ничего хорошего я в таком псевдодуализме не вижу — море реальных проблемы и весьма туманные преимущества.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[7]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 18.01.05 15:17
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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


В том-то и проблема. Интерфейс не "is derived from IBase", а просто "includes IBase". Но даже синтаксически, эта конструкция является наследованием, что действует разлагающе на неокрепшие умы и начинаются такие дерева (даже не дерева а графья), что только держись. Взять, к примеру, спецификацию SVG, которая вся описана именно в терминах интерфейсов на IDL. Не могу сейчас сказать на вскидку, но при подробном разборе я постоянно натыкался на разные противоречия, неоднозначности и несуразности, возникшие именно по причине наследования интерфейсов. А эти люди — отнюдь не мальчики, все-таки W3C.

AVK>Статически слишком ограничено, динамически слишком дорого.


Статически — это шаблоны C++, динамически — я сам делал нечто подобное в 90-лохматом году на чистом C. Там была концепция именно интерфейсов, реализованная через дополнительный препроцессор. Препроцессор нужен был лишь для автоматизизации процесса заполнения таблицы указателей на функции. И динамически было совсем недорого. Собрался было сделать совсем динамически — с ассоциированием по символьным именам, но тут случилось нашествие C++ и я тоже долго плевался от этой тупизны и кучи писанины с наследованием для реализации таких простых вещей...

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


У меня в структуре содержалась некая метаинформация (ID) интерфеса, которую я тоже собирался было сделать строковой для совсем уж динамических случаев.
Вообще-то, разрешение интерфесов по сигнатурам методов — это тот же самый пресловутый DLL Hell...
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[7]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 18.01.05 15:31
Оценка:
Здравствуйте, Poudy, Вы писали:

MS>>А программа с классами, но без наследования?


P>Это то же самое, как если бы классов не было вовсе.


Опять за рыбу деньги. Я уже приводил пример проекта, где и классы и ООП, но нет наследования.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[8]: : True OOP
От: Poudy Россия  
Дата: 18.01.05 17:58
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Опять за рыбу деньги. Я уже приводил пример проекта, где и классы и ООП, но нет наследования.

Да неее.... Я не о том. Уже писал, что введение наследования классов — это по большей части наследование реализации, механизм повторного использования кода. Если код используется повторно только через делегирование, то это просто неудобно с практической толки зрения для тех, кто программил с классами. Кстати, я думаю, что убийство наследование стало следствием больше параноидального стремления к инкапсуляции, чем следствием борьбы за гибкость. Ведь никто не заставляет тебя насильно использовать наследование. Зато тебя заставляют насильно не пользоваться наследованием.
Re[11]: : True OOP
От: Павел Кузнецов  
Дата: 19.01.05 03:58
Оценка:
AndrewVK,

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


> Вот только одна проблема — компоненты с такими интерфейсами не создашь.


Легко. Достаточно реализовать ставшую классической функцию QueryInterface. Это даже более гибко, чем наследование.

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


Есть много разделений, которые можно назвать искусственными, если принять определенную точку зрения, и с нее не сходить: интерфейс/класс, value-/reference- типы и т.п. В каждом из этих случаев есть как плюсы, так и минусы. Одним из преимуществ подхода к интерфейсам в Хероне является возможность легкого "преобразования" класса к интерфейсу даже если разработчик класса этого не предусмотрел.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[8]: : True OOP
От: LCR Россия lj://_lcr_
Дата: 19.01.05 07:33
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Багов с наследованием реализации в COM нет. Так как наследования

C>реализации нет как класса.

Я говорю "грабли", а не "баги". А грабли эти состоят в следующем: Предположим, у тебя есть объект, реализующий интерфейс I1. Разумеется у тебя есть реализация этих интерфейсов, скажем Impl1 и там реализована функция QueryInterface. Теперь нужен интерфейс I2, который включает I1. Но ты не можешь унаследовать реализацию Impl2 от Impl1, ибо Impl1::QueryInterface ничего не знает об интерфейсах, реализованных в Impl2. Ты вынужден тупо повторять реализацию Impl1. (Хорошо хоть, шаблоны есть: ).

C>COM — это просто стандарт на расположение методов в vtbl.


Ну здесь ты чуть слукавил — это немножко больше
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[12]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.01.05 10:26
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Легко. Достаточно реализовать ставшую классической функцию QueryInterface.



Это не КОП, это изврат. СОМ-образные решения на современном уровне развития никуда не годятся и выглядят примерно как корабли с паровой машиной сегодня.

ПК>Есть много разделений, которые можно назвать искусственными, если принять определенную точку зрения, и с нее не сходить: интерфейс/класс, value-/reference- типы и т.п.


Интерфейс/класс все таки вещи концептуальные. А вот насчет value/ref полностью согласен, но мне не известно решение в рамках статически типизированных языков, позволяющее это разделение убрать и не получить performance hit на порядок.

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


Как справедливо заметил Влад, то же самое можно прозрачно сделать без участия программиста. Да если и не сделать, потери от полиморфного вызова вместо статического не такие уж и ужасные. Вобщем наверное пригодно для time critical алгоритмов, но как концепция универсального языка имхо не катит.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[8]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.01.05 10:26
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

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


Действительно не понял. С Хероном это не сюда. Здесь обсуждают концепцию наследования. Более того, код, который обсуждался в этой ветке, привел WH и, насколшько я понял, имелся ввиду C#.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[9]: : True OOP
От: Костя Ещенко Россия  
Дата: 19.01.05 11:05
Оценка:
AndrewVK wrote:

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

>
> Действительно не понял. С Хероном это не сюда. Здесь обсуждают концепцию наследования. Более того, код, который обсуждался в этой ветке, привел WH и, насколшько я понял, имелся ввиду C#.

Меня ввел в заблуждение тот факт, что WH процитировал часть сообщения McSeem, где тот говорил о Хероне. Ну да Бог с этим.
Posted via RSDN NNTP Server 1.9
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[14]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.01.05 11:22
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

КЕ>Почему не годятся?


Потому что черезмерно сложны и неудобны.

КЕ>Если бы реализация QI могла быть сгенерирована компилятором при минимальной набивке текста, и вызов QI выглядел бы как просто как кастинг, это было бы достаточно современным?


Черт как всегда в деталях. Почитай что я писал по поводу реализации полиморфных интерфейсов.
Re[9]: Unintrusive Retroactive Polymorphism
Автор: AndrewVK
Дата: 06.01.05

А потом расскажешь как компилятор реализует такой универсальный QueryInterface автоматически, чтобы скорость работы была сравнима с вызовом виртуального метода, а вызывающий код на момент компиляции был недоступен.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[13]: : True OOP
От: Павел Кузнецов  
Дата: 19.01.05 14:59
Оценка:
AndrewVK,

> ПК> Легко. Достаточно реализовать ставшую классической функцию QueryInterface.


>

> Это не КОП, это изврат. СОМ-образные решения на современном уровне развития никуда не годятся и выглядят примерно как корабли с паровой машиной сегодня.

Легко можно представить, как это дело может быть автоматизировано при сохранении объектной модели.

> ПК> Одним из преимуществ подхода к интерфейсам в Хероне является возможность легкого "преобразования" класса к интерфейсу даже если разработчик класса этого не предусмотрел.


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


Да не в потерях дело... Дело в гибкости и разделении концепций: наследование отдельно, интерфейсы отдельно. Это как свободные функции: есть возможность расширения интерфейса класса без вмешательства в его устройство.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[15]: : True OOP
От: Павел Кузнецов  
Дата: 19.01.05 15:06
Оценка:
AndrewVK,

> КЕ>Если бы реализация QI могла быть сгенерирована компилятором при минимальной набивке текста, и вызов QI выглядел бы как просто как кастинг, это было бы достаточно современным?


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


Легко. В случае наследования тоже нельзя преобразовывать к произвольным интерфейсам, можно только к заранее объявленным. Соответственно, для эффективной реализации QueryInterface будет достаточно чего-нибудь такого:
class MyWidget : component [ Interface1, Interface2, Interface3 ... ]
{
   . . .
};

А в случаях, когда идет работа с самим классом, а не через интерфейсы, будут доступны все бонусы неинтрузивного преобразования к ссылкам на интерфейсы.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[16]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.01.05 15:31
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

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


Так тем Херон и отличается, что в нем интерфейсы заранее не объявляются.

ПК> Соответственно, для эффективной реализации QueryInterface будет достаточно чего-нибудь такого:

ПК>
ПК>class MyWidget : component [ Interface1, Interface2, Interface3 ... ]
ПК>{
ПК>   . . .
ПК>};
ПК>


Ну то есть вернулись к тому с от чего убегали .

ПК>А в случаях, когда идет работа с самим классом, а не через интерфейсы, будут доступны все бонусы неинтрузивного преобразования к ссылкам на интерфейсы.


Самому не смешно? Мне так очень.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[14]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.01.05 15:31
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Да не в потерях дело... Дело в гибкости и разделении концепций: наследование отдельно, интерфейсы отдельно.


Интерфейсы для внешней работы отдельно. Офигительная гибкость, ничего не скажешь. Вобщем только что вы родили монстра похлеще СОМ. Если теперь сравнить это с компонентной моделью дотнета или джавы все становится ясным.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[17]: : True OOP
От: Павел Кузнецов  
Дата: 19.01.05 15:50
Оценка:
AndrewVK,

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

>
> Так тем Херон и отличается, что в нем интерфейсы заранее не объявляются.

Никто не мешает добавить "рюшечку", нужную для поддержки COP, так чтобы она не мешала в остальных случаях.

> ПК>А в случаях, когда идет работа с самим классом, а не через интерфейсы, будут доступны все бонусы неинтрузивного преобразования к ссылкам на интерфейсы.

>
> Самому не смешно? Мне так очень.

Гм... Сейчас ребята из нашей конторы работают на C# для Web. Мне очень понравилось высказывание Миши Бергала по этому поводу (воспроизвожу по памяти): C# хорошо приспособлен для "склеивания" компонентов, но плохо для их написания. Собственно, я с ним согласен: шаблоны, неинтрузивные интерфейсы, свободные функции и т.п. — все это возможности, ориентированные на облегчение "внутрикомпонентного" программирования.
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[18]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.01.05 16:02
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>> Так тем Херон и отличается, что в нем интерфейсы заранее не объявляются.


ПК>Никто не мешает добавить "рюшечку", нужную для поддержки COP, так чтобы она не мешала в остальных случаях.


Вот лично мне языки, в которых для поддержки КОП нужны рюшечки и неинтересны.

ПК>Гм... Сейчас ребята из нашей конторы работают на C# для Web. Мне очень понравилось высказывание Миши Бергала по этому поводу (воспроизвожу по памяти): C# хорошо приспособлен для "склеивания" компонентов, но плохо для их написания.


Ниче ниче. Пусть еще попишут, а то больно рано выводы делают.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[14]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.01.05 16:43
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Забавно. COM стал паровой машиной на современном уровне развития. А вот CORBA, которая значительно старше и является значительно более низкоуровневым средством чем COM, живет и помирать не собирается (в мире Java, например).


Вот именно что низкоуровневым. CORBA предназначена для создания OO RPC. А СОМ это способ создания КО-программ на разных языках. Java, о которой ты упомянут, имеет собственную компонентную модель, ни на каком уровне не являющейся CORBA.

MS> И никто не говорит, что CORBA является паровой машиной в современном мире фотонных двигателей. На примере COM — очень хорошо виден "инженерный" подход Microsoft:


Ну да, конечно, во всем опять виновата МС. Хорошо, какую еще ты знаешь технологию создания компонентов?

MS>Наворотить кучу в бесплодных попытках решить задачу космического масштаба, после чего, убеждать весь мир в том, как это полезно для здоровья (ешь, ешь!). Далее, через некоторое время, объявить, что эта куча была (выражаясь политкорректно) стратегической ошибкой. И тут же начать воротить новую кучу, объявляя ее счастием для всех людей. Есть опасения, что дот-нет FW тоже будет объявлен страдегической ошибкой — это лишь вопрос времени.


Да-да. Кругом одни враги и главный из них МС. Очень правильный аргумент в техническом споре.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[15]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 19.01.05 17:12
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Вот именно что низкоуровневым. CORBA предназначена для создания OO RPC.


Это очень примитивное представление, лишь один аспект.

AVK>А СОМ это способ создания КО-программ на разных языках.


CORBA тоже является средством коммуникации между программами на разных языках. Без заявлений о всеобщем "щасте", поэтому и более низкоуровневым.

MS>> И никто не говорит, что CORBA является паровой машиной в современном мире фотонных двигателей. На примере COM — очень хорошо виден "инженерный" подход Microsoft:


AVK>Ну да, конечно, во всем опять виновата МС. Хорошо, какую еще ты знаешь технологию создания компонентов?


CORBA, например Только это — не технология, а простое и удобное средство для создания компонентной среды, на разных архитектурах, разных OS, и разных языках.

MS>>Наворотить кучу в бесплодных попытках решить задачу космического масштаба, после чего, убеждать весь мир в том, как это полезно для здоровья (ешь, ешь!). Далее, через некоторое время, объявить, что эта куча была (выражаясь политкорректно) стратегической ошибкой. И тут же начать воротить новую кучу, объявляя ее счастием для всех людей. Есть опасения, что дот-нет FW тоже будет объявлен страдегической ошибкой — это лишь вопрос времени.


AVK>Да-да. Кругом одни враги и главный из них МС. Очень правильный аргумент в техническом споре.


Ну так а что я могу поделать, если так оно получается. COM-то они хоронят! А сколько лопат было перелопачено? Теперь, вот, такое же дежа-вю с дот-нет. Навевает грустные мысли о тщетности усилий...
Да и потом, это не чисто технгический спор, он техническо-филосовский
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[15]: : True OOP
От: epflorov Россия www.epflorov.hotbox.ru
Дата: 19.01.05 20:53
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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


MS>>Забавно. COM стал паровой машиной на современном уровне развития. А вот CORBA, которая значительно старше и является значительно более низкоуровневым средством чем COM, живет и помирать не собирается (в мире Java, например).

А вчем если не секрет "большая низкоуровневость" CORBA перед COM?

AVK>Вот именно что низкоуровневым. CORBA предназначена для создания OO RPC. А СОМ это способ создания КО-программ на разных языках. Java, о которой ты упомянут, имеет собственную компонентную модель, ни на каком уровне не являющейся CORBA.

...skip...
AVK>Ну да, конечно, во всем опять виновата МС. Хорошо, какую еще ты знаешь технологию создания компонентов?

Есть такая партия — CCM CORBA component model Вполне формальная спецификация OMG. И реализации уже есть. Надо пробовать
Евгений Флоров
Re[16]: : True OOP
От: McSeem2 США http://www.antigrain.com
Дата: 19.01.05 21:10
Оценка:
Здравствуйте, epflorov, Вы писали:

E>А вчем если не секрет "большая низкоуровневость" CORBA перед COM?


Например, хотя бы тем, что в продвинутых случаях (на C++) надо самому писать управление сервантами. Но, во-первых, я бы даже назвал это преимуществом, поскольку дает больше свободы. Во-вторых, я имел дело только с ACE+TAO ORB. Не знаю, как оно в других.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[6]: : True OOP
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.01.05 00:32
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Краткий вывод такой: в данной ситуации оправдано использование "жирных" интерфейсов.


Кстати, вывод странный. Ситуации бываю разные.

"Жирный" интерфейс (если в том смысле что корневой класс имеет методы для работы с потомками) дает гибкость, но крадет статическую надежность. Разделение дает большую надежность, но меньшую гибкость. Далее если больше нужна гибкость, то выбираем "жирный", если надежность, то наоборот.

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

В общем, тут нужно смотреть на конкретную задачу.
... << RSDN@Home 1.1.4 beta 3 rev. 279>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: : True OOP
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.01.05 00:32
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Внимание вопрос: А как это сделать без наследования, определения конкретного типа и даункастов?


Например так:
interface INodeWithChildren
{
    INodeWithChildren this[int index] { get; }
    int Count { get; }
}

IFolder : INodeWithChildren
IArchive : INodeWithChildren
ITextFile : INodeWithChildren
IGraphicFile : INodeWithChildren
...
class TextFile
{
    INodeWithChildren this[int index] { get { throw new Exception(); } }
    int Count { get { return 0; } }
}
... << RSDN@Home 1.1.4 beta 3 rev. 279>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: [3]: : Re[2]: : True OOP
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.01.05 00:32
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Скорее у меня есть обратные примеры, когда ребята мучаются, пытаясь написать "обобщенные" переходники к ряду алгоритмов-методов на C#. Я это вижу у себя на работе, да и в Инете следы легко находятся:

ПК>http://www.wintellect.com/powercollections
ПК>http://codeproject.com/csharp/cs_functors.asp

В чем мучения то? Типа с шаблонами все проще? А вот по форумам такого не скажешь. Скорее на оборот.

ПК>И в C++/CLI, вне зависимости от легкого доступа к коллекциям .Net, решили делать STL.Net, что тоже должно наталкивать на определенные мысли...


Ну, да. А ветер от того что деревья качаются.


Тебя ни что не наводит на мысль, что STL.Net вводят для тех кто привык к STL и не привык к .Net. Ну, и для облегчения портирования софта?
... << RSDN@Home 1.1.4 beta 3 rev. 279>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: : True OOP
От: Костя Ещенко Россия  
Дата: 20.01.05 00:32
Оценка:
Здравствуйте, AndrewVK, Вы писали:

КЕ>>Если бы реализация QI могла быть сгенерирована компилятором при минимальной набивке текста, и вызов QI выглядел бы как просто как кастинг, это было бы достаточно современным?


AVK>Черт как всегда в деталях. Почитай что я писал по поводу реализации полиморфных интерфейсов.

AVK>Re[9]: Unintrusive Retroactive Polymorphism
Автор: AndrewVK
Дата: 06.01.05

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

Не понимаю где ты нашел проблему, QI реализуется тривиально. Для ооочень большого кол-ва интерфейсов он может быть реализован двоичным поиском, но поскольку как правило интерфейс можно привести только к небольшому кол-ву других интерфейсов, то обычный свитч — то что надо.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[16]: : True OOP
От: Poudy Россия  
Дата: 20.01.05 08:38
Оценка:
Здравствуйте, Cyberax, Вы писали:

>> Ну да, конечно, во всем опять виновата МС. Хорошо, какую еще ты знаешь

>> технологию создания компонентов?

C>GNOME (GNU Network Object Model), QT, Java Beans, Tcl/Tk...


Ты не понял вопроса к McSeem2. Компонент — это не значит "визуальный компонент". Компонент — это сложное понятие, паттерн проектирования. Компонент существует в рамках некоторого контейнера, обладает бинарным совместимым интерфейсом и т.д. То, что ты привел тут ваааще не при чем.
Re[10]: : True OOP
От: LCR Россия lj://_lcr_
Дата: 20.01.05 08:51
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>LCR пишет:


C>Тут ошибка. QI, который находится в IUnknown, реализуется ТОЛЬКО одним

C>объектом. То есть всегда будет вызываться QI у Impl2, который уже знает
C>о всех интерфейсах. Это, кстати, используется при аггрегировании
C>объектов — вызовы QI от аггрегированного интерфейса получает
C>аггрегирующий объект. Можно использовать и C++-наследование для
C>реализации COM'а.
Хм... Ладно, надо глянуть доку...
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[17]: : True OOP
От: Cyberax Марс  
Дата: 20.01.05 09:01
Оценка:
Poudy пишет:

>>> Ну да, конечно, во всем опять виновата МС. Хорошо, какую еще ты знаешь

>>> технологию создания компонентов?
> C>GNOME (GNU Network Object Model), QT, Java Beans, Tcl/Tk...
> Ты не понял вопроса к McSeem2. Компонент — это не значит "визуальный
> компонент". Компонент — это сложное понятие, паттерн проектирования.
> Компонент существует в рамках некоторого контейнера, обладает бинарным
> совместимым интерфейсом и т.д. То, что ты привел тут ваааще не при чем.

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

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[16]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 20.01.05 09:29
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

КЕ>Не понимаю где ты нашел проблему, QI реализуется тривиально.


Ну вот и расскажи как.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[16]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 20.01.05 09:29
Оценка:
Здравствуйте, McSeem2, Вы писали:

AVK>>Вот именно что низкоуровневым. CORBA предназначена для создания OO RPC.


MS>Это очень примитивное представление, лишь один аспект.


Но я что то не видел чтобы CORBA использовали для создания компонентов внутри одного процесса.

MS>CORBA тоже является средством коммуникации между программами на разных языках. Без заявлений о всеобщем "щасте", поэтому и более низкоуровневым.


Хорошо. Как называется технология, позволяющая скажем создавать GUI из CORBA-компонент? Нет, про CORBA 3.0 я знаю, но вот нормальная реализация ее где нибудь есть?

AVK>>Да-да. Кругом одни враги и главный из них МС. Очень правильный аргумент в техническом споре.


MS>Ну так а что я могу поделать, если так оно получается. COM-то они хоронят!


И правильно делают. А корбу хоть и не хоронят, но сама она таки благополучно умирает.

MS> А сколько лопат было перелопачено? Теперь, вот, такое же дежа-вю с дот-нет. Навевает грустные мысли о тщетности усилий...


Ага, а говоришь что не скрипишь зубами

MS>Да и потом, это не чисто технгический спор, он техническо-филосовский


Изначально он был именно техническим. Про СОМ я упомянул не из желания пофилософствовать о бренности сущего, а в качестве примера того, что получается когда пытаются применить КОП в нерассчитанных на это языках.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[16]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 20.01.05 09:39
Оценка:
Здравствуйте, Cyberax, Вы писали:

>> Вот именно что низкоуровневым. CORBA предназначена для создания OO RPC.


C>Как и COM...


COM и DCOM все таки не одно и то же.

>> А СОМ это способ создания КО-программ на разных языках. Java, о

>> которой ты упомянут, имеет собственную компонентную модель, ни на
>> каком уровне не являющейся CORBA.

C>COM не предназначен, а _позволяет_ создавать КО-программы, благодаря

C>_стандартизованному_ набору интерфейсов для взаимодействия визуальных
C>компонент

Здорово. А для чего тогда предназначен СОМ?

C>В CORBA тоже есть стандартизованные сервисы, например, Trading Service

C>или Persistance Service, которые ТОЖЕ позволяют писать КО-программы.
C>Просто CORBA до недавнего времени (GTK) не прикладывали к разработке
C>GUI.

Сдается мне ты путаешь CORBA и CORBA Component Model. Второе появилось намного позже, когда уже было поздно.

C>Принципиальных препятствий, опять же, нет.


Однако ж не используют
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[16]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 20.01.05 09:39
Оценка:
Здравствуйте, epflorov, Вы писали:

E>Есть такая партия — CCM CORBA component model


Есть.

E> Вполне формальная спецификация OMG. И реализации уже есть. Надо пробовать


Боюсь я что реализация ее на С++ не сильно проще СОМ будет.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[6]: : True OOP
От: WolfHound  
Дата: 20.01.05 10:17
Оценка:
Здравствуйте, VladD2, Вы писали:

WH>>Внимание вопрос: А как это сделать без наследования, определения конкретного типа и даункастов?

VD>Например так:
дык эта... мне всеравно понадобится инвормация которая есть только в конечных интерфейсах(IFolder, ITextFile...)
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[18]: : True OOP
От: Poudy Россия  
Дата: 20.01.05 11:26
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>А в чем проблема? CORBA и определяет бинарный протокол взаимодействия

C>объектов, и стандартизует определенные сервисы. С помощью CORBA
C>элементарно можно строить "компонентные" модели — просто это раньше не
C>делалось (в силу определенных причин).
Потому что тебе уже говорили: COM — это технология, а не стандарт. Правильнее сравнивать COM с CCM.
Re[7]: : True OOP
От: Poudy Россия  
Дата: 20.01.05 11:49
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH> дык эта... мне всеравно понадобится инвормация которая есть только в конечных интерфейсах(IFolder, ITextFile...)

Не относится напрямую к ответу Влада, но смотри за мыслью: ты избавишься от дацнкастов, если работа с конкретным типом будет происходить только в 2-х местах:
1. В месте, где создается объект.
— туда же идут обработчики конкретных событий, где явно указан тип или хозяин события лежит тут же в this.
2. В методах самого целевого типа (ZipArchive).
— туда же идут методы типизированные, вызываемые из методов типа.
— туда же идут обработчики событий от ZipArchive, в аргументах которых (событий) есть явный экземпляр целевого типа (ZipArchive).

Вот и выход: подумай обо всех местах, где тебе нужно приведение, и организуй их по-другому (с помощью Bridge и Strategy). Все варианты использования не реализуешь, но от большинства приведений можно избавиться.
Re[17]: : True OOP
От: Костя Ещенко Россия  
Дата: 20.01.05 13:30
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Костя Ещенко, Вы писали:


КЕ>>Не понимаю где ты нашел проблему, QI реализуется тривиально.


AVK>Ну вот и расскажи как.


Ок, еще раз: компилятор вполне способен из списка интерфейсов SomeItf, AnotherItf сгенерить код типа этого (имеется ввиду для небольшого кол-ва интерфейсов). Список интерфейсов указывается в явном виде.
UnspecifiedItfRef QI(ItfId Id)
{
switch(Id)
{
case SomeItf::Id: return ref<SomeItf>(this);
case AnotherItf::Id: return ref<AnotherItf>(this);
default: return NULL;
}
}
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[18]: : True OOP
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 20.01.05 14:51
Оценка:
Здравствуйте, Костя Ещенко, Вы писали:

КЕ>Ок, еще раз: компилятор вполне способен из списка интерфейсов SomeItf, AnotherItf сгенерить код типа этого (имеется ввиду для небольшого кол-ва интерфейсов). Список интерфейсов указывается в явном виде.


Блин. Фишка Херона как раз в том что список интерфейсов не указывается. А если его указать, то никаких QueryInterface не нужно, есть куда более производительные способы.
... << RSDN@Home 1.1.4 beta 3 rev. 299>>
AVK Blog
Re[19]: : True OOP
От: Костя Ещенко Россия  
Дата: 21.01.05 03:50
Оценка:
Здравствуйте, AndrewVK, Вы писали:

КЕ>>Ок, еще раз: компилятор вполне способен из списка интерфейсов SomeItf, AnotherItf сгенерить код типа этого (имеется ввиду для небольшого кол-ва интерфейсов). Список интерфейсов указывается в явном виде.


AVK>Блин. Фишка Херона как раз в том что список интерфейсов не указывается.


Блин. Ты же сам показал, что приведение в рантайме к любому стуктурно-совместимому интерфейсу
  • обойдется слишком дорого
  • опасно — опечатки и случайные совпадения приведут к серьезным неприятностям

    Волшебства не бывает, эта фишка в рантайме не работает. И не надо.

    AVK>А если его указать, то никаких QueryInterface не нужно, есть куда более производительные способы.


    Насчет ускорения мне приходит в голову только держать в vtbl вместо указателя на QI указатель на структуру данных, описывающую приведения. Или положить в vtbl не указатель, а саму структуру. Ты не это имел ввиду?

    Но у QI есть свои преимущества — единообразие с остальными функциями и гибкость в реализации QI, в том числе возможность определить ее вручную.
  • На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
    Re[5]: : True OOP
    От: alexanderfedin США http://alexander-fedin.pixels.com/
    Дата: 14.04.05 13:05
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

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

    WH>Допустим нам надо отобразить это дерево в пользовательском интерфейсе. Выглядить это должно так: с права дерево, а с лева отображение текущей ноды.
    WH>Как решать это с помощью наследования и даункастов понятно.
    WH>Имеем примерно такую иерархию
    WH>
    WH>INode
    WH>INodeWithChildren : INode
    WH>IFolder : INodeWithChildren
    WH>IArchive : INodeWithChildren
    WH>ITextFile : INode
    WH>IGraphicFile : INode
    WH>

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

    WH>Внимание вопрос: А как это сделать без наследования, определения конкретного типа и даункастов?

    Gang Of Four, "Design Patterns":
    INodeVisitor {
       accept(INode)
       accept(INodeWithChildren)
    }
    
    INode {
       virtual visit(INodeVisitor) { INodeVisitor.accept(this) }//здесь INodeVisitor уже знает тип
    }
    
    INodeWithChildren : INode {
       override visit(INodeVisitor) { INodeVisitor.accept(this) }//здесь INodeVisitor уже знает тип
    }
    
    IFolder : INodeWithChildren {
       override visit(INodeVisitor) { INodeVisitor.accept(this) }//здесь INodeVisitor уже знает тип
    }

    Или вы не об этом?
    Respectfully,
    Alexander Fedin.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.