Re[16]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 12.10.05 16:43
Оценка:
Здравствуйте, Dyoma, Вы писали:

E>>

E>>ООП базируется на трех китах: инкапсуляция, наследование и полиморфизм.

E>>Термин ООП я употребляю именно в этой интерпритации. Поэтому, если есть объект и есть методы (с полиморфизмом), но нет наследования (в принципе), то это уже не ООП.

D>Вообще-то ООП это объекты, обменивающиеся сообщениями. Отсюда следуют только инкапуляция и полиморфизм — потому как утверждается, что объекту сообщение послать можно, а как он на него будет реагировать это его дело. Наследование же появляется не во всех ООЯ, а только в (хотя бы динамически) типизированных.


См. Re[18]: Утиные истории vs ООП?
Автор: eao197
Дата: 12.10.05
, я там цитату из Wikipedia привел. По поводу отсутствия наследования в некоторых языках там сказано:

(Object-based languages do not always have inheritance)


т.е. object-based, а не object-oriented.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[17]: Утиные истории vs ООП?
От: Dyoma Россия http://www.livejournal.com/users/dyomap/
Дата: 12.10.05 17:09
Оценка: 1 (1)
Здравствуйте, eao197, Вы писали:

E>См. Re[18]: Утиные истории vs ООП?
Автор: eao197
Дата: 12.10.05
, я там цитату из Wikipedia привел. По поводу отсутствия наследования в некоторых языках там сказано:

E>

E>(Object-based languages do not always have inheritance)


E>т.е. object-based, а не object-oriented.


А вот еще одно
Автор: _vovin
Дата: 06.10.05
. Вопрос: какое в данном случае адекватнее?
Imho в Wikipedia определение от жизни, т.е. не важно о каких идеях думали отцы основатели, важно во что это на сегодня вылилось. А выливали ООП в жизнь, C++, ObjectPascal, а потом еще и Java с C#. Думаю, что как минимум 90% ООП на планете я этим списком покрыл. Отсюда и упоминание про остальные варианты в скобках.
В этой же дискусии ты идешь уже не от жизни (duck-typing не имеет такого распостранения), а от идей. Так что и определение надо брать идейное . Либо дискуссию стоило назвать "Утиные истории vs mainstream ООП".

Dyoma
ALMWorks
http://deskzilla.com/
Re[13]: Утиные истории vs ООП?
От: Cyberax Марс  
Дата: 12.10.05 17:10
Оценка:
eao197 wrote:

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

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

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

> Т.е., если мне нужен класс "чемодан", то я сначала должен определить

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

Ну да, вполне логично.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 2.0 beta
Sapienti sat!
Re[18]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 12.10.05 17:22
Оценка:
Здравствуйте, Dyoma, Вы писали:

D>А вот еще одно
Автор: _vovin
Дата: 06.10.05
.


А вот еще одно его высказывание: Re[5]: Утиные истории vs ООП?
Автор: Andrei N.Sobchuck
Дата: 08.10.05


D> Вопрос: какое в данном случае адекватнее?


Действительно, какое?
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[19]: Утиные истории vs ООП?
От: Dyoma Россия http://www.livejournal.com/users/dyomap/
Дата: 12.10.05 17:41
Оценка: +1
Здравствуйте, eao197, Вы писали:

E>А вот еще одно его высказывание: Re[5]: Утиные истории vs ООП?
Автор: Andrei N.Sobchuck
Дата: 08.10.05


D>> Вопрос: какое в данном случае адекватнее?


E>Действительно, какое?


Ну и программирование и дизайн на Smalltalk всеравно объектно-ориентированные. Вид программирования определяется все-таки патернами, и способом декомпозиции задачи. Патерны одни и теже, баланс несколько между ними разный, ну так он и между C++ — java разный. А язык — да, язык обозвали не совсем правильно (я там
Автор: Dyoma
Дата: 08.10.05
, ксати, на эту тему высказывался).

Dyoma
ALMWorks
http://deskzilla.com/
Re[17]: Утиные истории vs ООП?
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.10.05 04:21
Оценка: 56 (4) +1
Здравствуйте, eao197, Вы писали:

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

ДА какое исключение? Речь идет о том, что ты получишь compile-time error! Потому, что чемодан не работает как подставка. Точка.
Если ты попытаешься привести чемодан динамически, то получишь исключение ровно в том месте, где ты попытался его привести. А не при применении.

Вообще, я вижу у тебя отсутствие понимания двух вещей:
1. Наследование и реализация интерфейсов — разные вещи. То, что в C++ это выглядит одинаково, лучше считать случайным совпадением. Рекомендую как можно быстрее освоить разницу между этими понятиями. Иначе твои представления об ООП не будут соответствовать современному уровню.
2. Помимо наличия самой ошибки, важны три фактора:
— последствия. Хуже всего: недетерминированное поведение в продакшн системе. Лучше всего: запись в лог и выполнение корректной fallback стратегии
— место проявления. Хуже всего: ошибка обнаруживается неопределенно далеко от того места, где она сделана. Лучше всего: ошибка обнаруживается непосредственно там, где ее можно исправить
— время проявления. Хуже всего: ошибка проявляется иногда, при трудновоспроизводимом стечении обстоятельств. Лучше всего: есть детерминированный момент, когда ошибка, если есть, заведомо себя проявит.

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

При использовании настоящих интерфейсов, мы либо получим ошибкупри компиляции и именно в том месте, где мы присваиваем хакера в слот для утки, либо в рантайме — в том же месте. При этом в рантайме мы получим детерминированное поведение, которое не приведет нас в тюрьму.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 13.10.05 06:44
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

S>ДА какое исключение? Речь идет о том, что ты получишь compile-time error! Потому, что чемодан не работает как подставка. Точка.

Совсем не точка. Мы с AndrewVK говорили об объектах, которые поддерживают несколько интерфейсов. В частности, чемодан поддерживает: "контейнер для ручной клади", "хранилище хлама", "подставка". Речь шла о том, что если чемодан как подставку использовать для не подходящей вещи, то он сломается, а мы поимеем проблемы. На что я возразил, что интерфейс "подставка", реализованный СтекляннымЖурнальнымСтоликом для того же самого телефизора так же не подойдет, получится исключения. Поэтому все compile-time проверки в этом случае идут лесом.

S>Вообще, я вижу у тебя отсутствие понимания двух вещей:

S>1. Наследование и реализация интерфейсов — разные вещи. То, что в C++ это выглядит одинаково, лучше считать случайным совпадением. Рекомендую как можно быстрее освоить разницу между этими понятиями. Иначе твои представления об ООП не будут соответствовать современному уровню.

Ok.

Интересная, однако, тенденция. Первоначально ООП вообще не подразумевало наследования (Re[3]: Снова о типизации :)
Автор: _vovin
Дата: 06.10.05
), затем появились постулаты инкапсуляция/полиморфизм/наследование, теперь сюда же еще и интерфейсы добавляются. Имхо, если понятие такое аморфное и видоизменяется со временем, то это отнюдь не строгое понятие. А может и не понятие вовсе.

S>2. Помимо наличия самой ошибки, важны три фактора:

S>- последствия. Хуже всего: недетерминированное поведение в продакшн системе. Лучше всего: запись в лог и выполнение корректной fallback стратегии
S>- место проявления. Хуже всего: ошибка обнаруживается неопределенно далеко от того места, где она сделана. Лучше всего: ошибка обнаруживается непосредственно там, где ее можно исправить
S>- время проявления. Хуже всего: ошибка проявляется иногда, при трудновоспроизводимом стечении обстоятельств. Лучше всего: есть детерминированный момент, когда ошибка, если есть, заведомо себя проявит.

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

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

Все перечисленные тобой проблемы постоянно проявляются и в программах со статической типизацией. В которых совершенно нет duck typing-а.

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


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

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

А что в итоге: ошибки в ПО все равно есть. И для потребителя программ это главное. Ему без разницы, статическая там типизация или динамическая. Раз программа упала, значит недотестировали. Или условия задачи не поняли. Или реализация со всеми ограничениями наследования/интерфейсов оказалась настолько запутанной, что в поведении программы вообще мало кто разбирается.

Статическая типизации и "современный" ООП применяются повсемесно. Но повышения надежности программ и сокращения сроков разработки не происходит. Duck typing применяется гораздо реже, многие из моих оппонетнов в данном топике, вероятно, вообще его не применяют. Но при этом пытаются доказать, что duck typing менее надежен, чем статическая типизация и интерфейсы. Может быть вы и правы.

Хотя, с другой стороны, может быть duck typing позволяет тратить меньше времени на проектирование/разработку, а освободившееся время посвящать более тчательному и всестороннему тестированию? Может быть здесь сработает тот же принцип, что и при программировании на динамических языках: ошибок гораздо меньше, чем предполагаешь в начале. А из-за чего -- точно не понятно. Может быть потому, что больше тестируешь. Может быть потому, что код получается компактным. Может быть потому, что меньшим количеством сущностей оперировать нужно. Много мелких факторов, которые складываются и дают совершенно неожиданный для тебя результат.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[19]: Утиные истории vs ООП?
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.10.05 08:08
Оценка: +1
Здравствуйте, eao197, Вы писали:

E>Совсем не точка. Мы с AndrewVK говорили об объектах, которые поддерживают несколько интерфейсов. В частности, чемодан поддерживает: "контейнер для ручной клади", "хранилище хлама", "подставка".

Нет. Речь шла о duck vs normal тайпинге.
E>Речь шла о том, что если чемодан как подставку использовать для не подходящей вещи, то он сломается, а мы поимеем проблемы. На что я возразил, что интерфейс "подставка", реализованный СтекляннымЖурнальнымСтоликом для того же самого телефизора так же не подойдет, получится исключения. Поэтому все compile-time проверки в этом случае идут лесом.
Не идут они никаким лесом. Потому, что стратегия реакции на постановку чего-либо является частью семантики интерфейса подставки. У нее есть детерминированный способ отреагировать на телевизор — выкинуть ArgumentException или InvalidOperationException. Это в корне отличается от ситуации, когда мы просто передаем наш телевизор в случайно попавшийся метод "поставить". А этот метод, в свою очередь, может попытаться выполнить над поставленной на него вещью какую-то не ту операцию. И т.д.

E>Ok.

E>Интересная, однако, тенденция. Первоначально ООП вообще не подразумевало наследования (Re[3]: Снова о типизации :)
Автор: _vovin
Дата: 06.10.05
), затем появились постулаты инкапсуляция/полиморфизм/наследование, теперь сюда же еще и интерфейсы добавляются.

E> Имхо, если понятие такое аморфное и видоизменяется со временем, то это отнюдь не строгое понятие. А может и не понятие вовсе.
Я тебе очень советую почитать научную литературу на эту тему. Ну, к примеру, теорию классификации на jot.fm
E>Все перечисленные тобой проблемы постоянно проявляются и в программах со статической типизацией. В которых совершенно нет duck typing-а.
Ну и что? Давай теперь выкинем на помойку средства по предотвращению таких ошибок, и запользуем средства по их внесению.

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


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


E>А что в итоге: ошибки в ПО все равно есть. И для потребителя программ это главное. Ему без разницы, статическая там типизация или динамическая. Раз программа упала, значит недотестировали. Или условия задачи не поняли. Или реализация со всеми ограничениями наследования/интерфейсов оказалась настолько запутанной, что в поведении программы вообще мало кто разбирается.


Я не вижу никаких причин для программы с дак-тайпингом стать сильно проще.

E>Статическая типизации и "современный" ООП применяются повсемесно. Но повышения надежности программ и сокращения сроков разработки не происходит.

Происходит и еще как.
Основные причины падения и неустойчивостей происходят от:
— использования унаследованных технологий (покажите мне хоть один buffer overrun в управляемом приложении! А в неуправляемых их ежегодно отлавливают).
E>Duck typing применяется гораздо реже, многие из моих оппонетнов в данном топике, вероятно, вообще его не применяют. Но при этом пытаются доказать, что duck typing менее надежен, чем статическая типизация и интерфейсы. Может быть вы и правы.
Я не понимаю, как убирание средства контроля правильности программы может помочь контролю правильности программы.

E>Хотя, с другой стороны, может быть duck typing позволяет тратить меньше времени на проектирование/разработку, а освободившееся время посвящать более тчательному и всестороннему тестированию? Может быть здесь сработает тот же принцип, что и при программировании на динамических языках: ошибок гораздо меньше, чем предполагаешь в начале. А из-за чего -- точно не понятно. Может быть потому, что больше тестируешь. Может быть потому, что код получается компактным. Может быть потому, что меньшим количеством сущностей оперировать нужно. Много мелких факторов, которые складываются и дают совершенно неожиданный для тебя результат.

Может быть. Но очень уж сомнительно.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Утиные истории vs ООП?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 13.10.05 09:02
Оценка:
Здравствуйте, eao197, Вы писали:

AVK>>Видимо ты не понял о каких эффектах шла речь. Я говорил не о том, что метод не полностью описывается контрактом, а о том, что (в полиморфном коде) нет никакой гарантии что за методом Add стоит именно то, что тебе кажется правильным.


E>Странно, я думал, что в нашем разговоре это подразумевается.


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

AVK>>Для этого нужно понять что именно телевизор был причиной.


E>Так ведь в языках, в которых сильная поддержка run-time, мы об этом сразу узнаем. По stack trace.


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

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


E>Ты знаешь, это как расхождение теории с практикой. В теории (интерфейсы + проверка компилятора) все OK. На практике -- через несколько часов работы приложение падает.


Это некорректный прием спора.

AVK>>Вариантов много. Один из — контроль соотвествия контрактов компилятором и рантаймом. В случае интерфейса формальный контракт есть, в случае duck typing нету, потому что с сигнатурой никакой семантики не связано.


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


Тем не менее в случае явно задекларированного интерфейса вероятность несоответствия существенно больше.

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


E>Именно об этом я до сих пор и говорил. Выкинуто такое исключение.

E>Только вот его тот, кто использует данный класс подставки, не ждал.

А исключение тем и отличается от кодов возврата, что его ждать необязательно.

E>>> А не так потому, что вмешивается в дело "локальность ссылок" -- объекты используются в очень ограниченных контекстах, где легко отслеживать их типы.


AVK>>Звучит круто, но совершенно непонятно.


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


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

AVK>> А если система компонентная?


E>Вот не знаю. Есть у меня подозрение, что не все будет ладно в датском королевстве.


А у меня скорее уверенность (при широкомасштабном применении).

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


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


E>Про высококвалифицированных спецов не могу сказать. Пока я только про свой опыт сужу.


Т.е. то, что реальный софт пишут команды, ты в своей оценке не учитываешь?

AVK>>Да и не много на практике случаев, когда методы с одинаковой сигнатурой и похожей семантикой есть, а общего интерфейса нет. Так вот, навскидку, в .NET Framework я такого не припомню.


E>Имхо, .NET Framework -- это не очень хороший для данной темы пример. Все же в нем повторно реализованы многократно пройденные вещи.


Говори уж прямо — не очень хороший для твоей точки зрения. А в качестве примера типичной современной библиотеки он очень хорош. Можешь еще джавовскую либу поглядеть, но только там еще веселее будет, Sun, в отличие от MS, умеет применять интерфейсы широко и с умом, особенно в свежем коде.
... << RSDN@Home 1.2.0 alpha rev. 617>>
AVK Blog
Re[20]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 13.10.05 09:06
Оценка:
Здравствуйте, Sinclair, Вы писали:

E>>Совсем не точка. Мы с AndrewVK говорили об объектах, которые поддерживают несколько интерфейсов. В частности, чемодан поддерживает: "контейнер для ручной клади", "хранилище хлама", "подставка".

S>Нет. Речь шла о duck vs normal тайпинге.

Речь шла вот о чем (Re[6]: Утиные истории vs ООП?
Автор: eao197
Дата: 12.10.05
):

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


Поясню свою мысль. Берем C++. У нас есть класс:
class Suitcase
    {
    public :
        void put_on_top( Weight weight )
            {
                if( weight > Weight::kg( 2 ) )
                    throw Suitcase_Absolutly_Crashed();
                ...
            }
    };

Это чужой класс, изменять мы его не можем.

Затем нам в программе потребовались подставки, для чего мы делаем интерфейс:
class Pedestal
    {
    public :
        virtual void put_on_top( Weight weight ) = 0;
    };
[/code] 

Реализуем этот интервейс в разных классах, в том числе и в злополучном СтеклянномЖурнальномСтолике:
[ccode]
class Glass_Magazine_Table : public Pedestal
    {
    public :
        virtual void put_on_top( Weight weight )
            {
                if( weight > Weight::kg( 10 ) )
                    throw Invalid_Weight();
                ...
            }
    };


И пишем какой-то метод:
void unpack_tv_and_put_on( Tv_Box & tv_box, Pedestal & pedestal )
    {
        Tv & tv = tv_box.unpack();
        pedestal.put_on_top( tv.weight() );
    }


Через какое-то время нам приходится использовать в качестве подставки чемодан. Просто так в unpack_tv_and_put_on его не передашь. Делаем вокруг чемодана обертку:
class Suitcase_As_Pedestal : public Pedestal
    {
    public :
        Suitcase_As_Pedestal( Suitcase & s ) : s_( s ) {}
        virtual void put_on_top( Weight weight ) { s_.put_on_top( weight ); }
    };


После чего компилятор нам дает добро на написание кода:
void unpack_tv_in_new_flat( Tv_Box & tv_box )
    {
        Suitcase my_biggest_suitcase;
        Suitcase_As_Pedestal poor_pedestal( my_biggest_suitcase );
        unpack_tv_and_put_on( tv_bod, poor_pedestal );
        ...
    }


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

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

class Suitcase_As_Pedestal : public Pedestal
    {
    public :
        Suitcase_As_Pedestal( Suitcase & s ) : s_( s ) {}
        virtual void put_on_top( Weight weight )
            {
                try
                    {
                        s_.put_on_top( weight );
                    }
                catch( const Suitcase_Absolutly_Crashed & )
                    {
                        // Должны породить то, что якобы ожидают.
                        throw Invalid_Weight();
                    }
                // Надеемся, что в Suitcase не будут появляться новые
                // исключения со временем.
            }
    };


Хотя можно было бы сделать просто:
template< class T >
void unpack_tv_and_put_on( Tv_Box & tv_box, T & pedestal )
    {
        Tv & tv = tv_box.unpack();
        pedestal.put_on_top( tv.weight() );
    }

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

Самое важное возражение тут уже приводилось не раз: при развитии проекта не специфицированные формальным образом (т.е. средствами языка в коде) соглашения об интерфесах станут кошмаром в большом проекте и при сопровождении.

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

E>>Речь шла о том, что если чемодан как подставку использовать для не подходящей вещи, то он сломается, а мы поимеем проблемы. На что я возразил, что интерфейс "подставка", реализованный СтекляннымЖурнальнымСтоликом для того же самого телефизора так же не подойдет, получится исключения. Поэтому все compile-time проверки в этом случае идут лесом.

S>Не идут они никаким лесом. Потому, что стратегия реакции на постановку чего-либо является частью семантики интерфейса подставки. У нее есть детерминированный способ отреагировать на телевизор — выкинуть ArgumentException или InvalidOperationException. Это в корне отличается от ситуации, когда мы просто передаем наш телевизор в случайно попавшийся метод "поставить". А этот метод, в свою очередь, может попытаться выполнить над поставленной на него вещью какую-то не ту операцию. И т.д.

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

Так что статическая типизация и интерфейсы не защищают нас от преднамеренного использования неподходящих объектов в несвойственных им ролях.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[19]: Утиные истории vs ООП?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 13.10.05 09:13
Оценка: 16 (2) +1
Здравствуйте, eao197, Вы писали:

E>Статическая типизации и "современный" ООП применяются повсемесно. Но повышения надежности программ и сокращения сроков разработки не происходит. Duck typing применяется гораздо реже, многие из моих оппонетнов в данном топике, вероятно, вообще его не применяют. Но при этом пытаются доказать, что duck typing менее надежен, чем статическая типизация и интерфейсы. Может быть вы и правы.


Ты зря думаешь что этот duck typing никто не применял и не применяет. В свое время, когда я писал на Java, я этот duck typing применял довольно широко (при помощи рефлекшена). А вот в C# я от него постепенно полностью отказался? Знаешь почему? Потому что этот duck typing приводит к слишком сильным связям в программе. И так перегруженная функционалом сигнатура перегружается еще больше (не говоря уж о том, что перестают работать автоматические рефакторинги). Мне, при разработке класса, приходится помнить о том, что какая то внешняя механика ожидает такую и именно такую сигнатуру и просто так ее трогать нельзя. Простейшее добавление еще одного параметра превращается в танцы с бубном, когда либо публичный метод надо перегружать (только ради сторонней механики), либо править этот метод во всех спользуемых сторонней механикой классов (а это тоже непросто определить).
Поэтому в .NET я в таких случаях использую атрибут. Т.е. привязка к методу происходит не по его сигнатуре, а по наличию специального, только для данной механики созданного атрибута.
Теперь что касается чужих классов, которые я поменять не могу. Для работы с такими классами, помимо создания оберток, есть еще масса способов. Например можно просто отнаследоваться. Или декларативно описать связь где нибудь вовне.
... << RSDN@Home 1.2.0 alpha rev. 617>>
AVK Blog
Re[13]: Утиные истории vs ООП?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 13.10.05 09:23
Оценка:
Здравствуйте, eao197, Вы писали:

E>Т.е. это нас приводит к тому, что в приложении мы должны оперировать двумя разными понятиями: интерфейс (контракт) и реализация (класс). Мы не можем создать класс без того, чтобы ранее определить его интерфейс. Т.е., если мне нужен класс "чемодан", то я сначала должен определить интерфейс "чемодан", а затем сделать его реализацию в виде класса "обычный_чемодан". Как следствие, место создания экземпляра я должен максимально локализововать (чтобы имя "обычный_чемодан" было только где-нибудь в одном месте программы), а везде, где мне нужен чемодан, я должен оперировать только интерфейсом "чемодан". Так получается?


Немного не так. Во-первых — создание интерфейса чемодан имеет смысл только если есть некий внешний по отношению к чемоданам код, который все чемоданы (и только чемоданы) обрабатывает по единым правилам. Елси же такого кода нет, то и интерфейс вводить не нужно. Интерфейс должен отражать некий аспект (обычно интерфейс это прилагательное, в отличие от класса — существительного) — например "носимый", "хранимый", "хранящий" и т.п.
... << RSDN@Home 1.2.0 alpha rev. 617>>
AVK Blog
Re[22]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 13.10.05 09:29
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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


А я о том, что когда я начинаю использовать твой класс, я понимаю, что делает метод Add в твоем классе.

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


AVK>Тем не менее в случае явно задекларированного интерфейса вероятность несоответствия существенно больше.


Не думаю: Re[20]: Утиные истории vs ООП?
Автор: eao197
Дата: 13.10.05
.

E>>Вот не знаю. Есть у меня подозрение, что не все будет ладно в датском королевстве.


AVK>А у меня скорее уверенность (при широкомасштабном применении).


Вот это существенно.

E>>Про высококвалифицированных спецов не могу сказать. Пока я только про свой опыт сужу.


AVK>Т.е. то, что реальный софт пишут команды, ты в своей оценке не учитываешь?


Блин, да я же не агитирую всех за тотальное использование duck typing-а. Я хочу понять границы его применимости.
Командная разработка, действительно, вряд ли выиграет от использования duck typing-а. Это очень серьезный минус для duck typing-а.

E>>Имхо, .NET Framework -- это не очень хороший для данной темы пример. Все же в нем повторно реализованы многократно пройденные вещи.


AVK>Говори уж прямо — не очень хороший для твоей точки зрения. А в качестве примера типичной современной библиотеки он очень хорош.


В качестве универсальной системной библиотеки, не спорю.
Только, имхо, duck typing показывает свои преимущества при написании прикладного кода, который интегрирует в себе совершенно разные библиотеки. Вот потребуется кому-то читать данные как из файла, так из сокета, так из какого-то хитрого устройства ввода-вывода. Средства для чтения из сокета и файла он возьмет из .NET Framework. Для для устройства есть готовая либа, которая сделана совершенно не в духе .NET. Как сделать код чтения унифицированным? Написать интерфейс над библиотекой устройства. Разница в том, как этот интерфейс будет выглядеть в случае формализованных интерфейсов и duck typing-а. В некоторых случаях duck typing менее геморройный.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[23]: Утиные истории vs ООП?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 13.10.05 09:55
Оценка:
Здравствуйте, eao197, Вы писали:

E>А я о том, что когда я начинаю использовать твой класс, я понимаю, что делает метод Add в твоем классе.


Разница только в том, что, в полиморфных алгоритмах, интерфейс один, а методов (каждый со своей семантикой) ровно столько, сколько теоретически в этот алгоритм может попасть классов.

AVK>>Т.е. то, что реальный софт пишут команды, ты в своей оценке не учитываешь?


E>Блин, да я же не агитирую всех за тотальное использование duck typing-а. Я хочу понять границы его применимости.


ИМХО затычки и заплатки. Либо какая то сверхуниверсальная механика.

E>Только, имхо, duck typing показывает свои преимущества при написании прикладного кода, который интегрирует в себе совершенно разные библиотеки.


Какие?

E> Вот потребуется кому-то читать данные как из файла,


System.IO

E> так из сокета,


System.Net

E> так из какого-то хитрого устройства ввода-вывода.


System.IO.Ports

E>Для для устройства есть готовая либа, которая сделана совершенно не в духе .NET.


Пример такой либы в студию.
... << RSDN@Home 1.2.0 alpha rev. 617>>
AVK Blog
Re[24]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 13.10.05 10:10
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Разница только в том, что, в полиморфных алгоритмах, интерфейс один, а методов (каждый со своей семантикой) ровно столько, сколько теоретически в этот алгоритм может попасть классов.


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

E>>Блин, да я же не агитирую всех за тотальное использование duck typing-а. Я хочу понять границы его применимости.


AVK>ИМХО затычки и заплатки. Либо какая то сверхуниверсальная механика.


Пока очень похоже на то. Т.е. не полноценная парадигма, а один из способов обобщенного программирования.

AVK>Пример такой либы в студию.


Это я с ходу нафантазировал. А вообще толкнуло меня на это обсуждение вот что: Re[22]: Следующий язык программирования
Автор: eao197
Дата: 08.10.05
.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Утиные истории vs ООП?
От: Poudy Россия  
Дата: 13.10.05 10:17
Оценка: -2
Здравствуйте, VladD2, Вы писали:
S>>Однако, как я подозреваю, микрософтеры сделали стрим таким потому, что считают свойства CanXXX не неотъемлемо приданными на уровне класса, а изменчивыми за время жизни одного и того же стрима. Это — единственное оправдание подобной архитектуры.

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


Думаю, что это они сделали очень грамотно, а не по глупости. Такие же фишки есть в IList, IDictionary (IsReadOnly, IsFixedSize), в PropertyInfo (CanRead, CanWrite) и т.д. На мой взгляд это единственно правильное решение, потому как ReadonlyCollection, FixedCollection, WritableProperty и прочее — просто чушь о ерунде. Так же как IFixedCollection. Или IChangeableCollection. Совершеннейшая ерундистика с прагматической точки зрения выносить в метаданные то, что можно определить свойством.
Re[25]: Утиные истории vs ООП?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 13.10.05 10:27
Оценка:
Здравствуйте, eao197, Вы писали:

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


Но всегда >1, иначе просто смысла нет. Следовательно даже в самых удачных случаях duck typing значительно тяжелее контроллировать.

AVK>>Пример такой либы в студию.


E>Это я с ходу нафантазировал.


Ну вот а я за все время работы с разнообразнейшими либами ни разу такой потребности не ощущал.
... << RSDN@Home 1.2.0 alpha rev. 617>>
AVK Blog
Re[26]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 13.10.05 10:31
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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


AVK>Но всегда >1, иначе просто смысла нет. Следовательно даже в самых удачных случаях duck typing значительно тяжелее контроллировать.




На C++ных шаблонах такого не замечал.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Утиные истории vs ООП?
От: Павел Кузнецов  
Дата: 14.10.05 16:26
Оценка: +1
AndrewVK,

> A>Видишь ли, понятие хорошего стиля у каждого свое.

>
> Если бы это было так, то создание качественного кода командой было бы невозможно.

ОК. У каждой команды свое.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Утиные истории vs ООП?
От: Павел Кузнецов  
Дата: 14.10.05 16:36
Оценка: +1 :)
Dyoma,

> Исторически статическая типизаия использовалась как способ дать компилятору подскази для построения эффективного кода. Например, С++ компилятор, строит vtbl для класса размером не на все возможные (в системе) сообщения, а только на определенные в этом классе. В Smalltalk, например, такой оптимизации не делается. По этому если Smalltalk объект получает "непонятное" для него сообщение, то он кидает исключение, а C++ объект начинает вести себя непредсказуемым образом (что почти всегда приводит к GPF, а иногда к порче данных или странному поведению).


Можно пояснить мысль поподробнее относительно того, что ты понимаешь под передачей объекту C++ "непонятного" для него сообщения?
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.