Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>А так ли много потеряно? SM>Как-то не убеждают меня приведенные аргументы, что мы идем неверным путем. Сейчас я попробую каждый из них прокомментировать. Я не настаиваю на своей точке зрения — напротив, очень хотелось, чтобы, если я чего-то не вижу, мне это объяснили. Поскольку я совершенно не разбираюсь, в частности, в SmallTalk и мое мнение о нем основано на той самой статье, на которую ссылается _vovin.
SM>Итак, концепция ООП чудовищно изуродована и сужена? То есть многое, что легко и красиво можно реализовать при изначальной трактовке ООП, становится сложным и запутанным, а подчас и невозможным? SM>Сразу оговорюсь,
_>>Но это является пагубным упрощением, которое практически сводит на нет всю идею объектного подхода. Где главным выигрышем является возможность непосредственного манипулирования динамическим миром объектов посредством гибкой операции посылки сообщения, минуя привычную чрезмерную серию трансформаций текст->код->запуск->взаимодействие->результаты->текст->... SM>Не понимаю... SM>Во-первых, откуда хвост "результаты->текст->..."? Что это за процесс описывается, создание программы, что ли?
Именно так. Еще не придумано хороших математических методов описания задачи, когда исходный код можно создать сразу и правильно. Либо приходится дизайнить приложения, потом вбивать код, а потом hack until it works. Либо идти путем постеменного наращивания функциональности с контролем корректности на каждом шаге.
В любом случае получается эволюционный замкнутый процесс от требований к тестированию и так до бесконечности.
Поэтому вот этот микро-цикл разработки является критичным (вспоминаю как мне приходится по десять минут перегрузать жававский веб-сервер ради малюсенького изменения). Объектный подход позволяет этот цикл сделать минимальным из возможных. Ты по ходу добавляешь код или корректируешь состояние объект чтобы увидеть как дальше оно работает.
SM>Во-вторых, как переход от концепции вызова метода к концепции посылки сообщения позволит обойтись без текста, или кода, или взаимодействия? Ну ладно еще без запуска — при определенной организации создаваемого кода его может быть просто не нужно как-то особо запускать...
Текст остается. Просто текст является носителем информации, которую ты хочешь передать в объектый мир посредством специализированных объектов — браузеров, рабочих областей и т.д.
Но суть посылки сообщения немного не в этом. Эта достаточно общая операция, которая позволяет создавать систему с рекурсивным дизайном, т.е. ту, в которой даже малые ее части могут обладать теми же возможностями, что и система в целом.
Для примера — сообщение можно послать и числу, и вызовется соответветствующий метод. Или можно модифицировать посылку сообщений для объекта так, что они будут упаковываться и передаваться по сети. Таким образом мы получаем SOA, которая сейчас так рекламируется как замена ООП (а технически SOA оказалось всего лишь специализированной реализацией посылки сообщения — всего лишь одна треть ООП ).
SM>А насчет описанного в предлагаемой статье примера процесса разработки можно сказать: такой подход отличается от обычного лишь тем, что окна отладчика все время висят на экране. Все равно в какие-то моменты времени программист ими пользуется, а в другие — пишет код и реализует методы, и вот тогда ему отладчик совершенно не нужен. Иногда, конечно, нужен (ради того самого контекста выполнения) — но ведь для редактирования кода не обязательно выходить из режима отладки, можно продолжать любоваться контекстом.
В общем так получается, что в отладке разработка половину времени проходит, когда-то больше, когда-то меньше. Это больше, чем компиляция. Кроме того, что только что вбитая строчка сразу же выполнилась, соответственно ошибки типов вылазят сразу, так еще и корректность легко контролируется. Вот от этого отказаться трудно. Разве что разработка в стиле TDD снижает степень утраты.
_>>Кое-что на эту тему можно прочитать здесь. SM>Стало жутко интересно, прочитал. Не убедили
SM>Однородность языка — это приятно, но нельзя из нее делать кумира. Она полезна лишь когда упрощает разработку программ на этом языке. В остальных случаях она значима только для научных изысканий, которые, быть может, и приведут в итоге к революции в программировании, но при этом не имеют ничего общего с повседневными решаемыми задачами.
Однородность и предсказуемость решает. Она очень и очень упрощает разработку. Это не стоит игнорировать особенно учитывая человеческое 7+-2.
Сколько человеко-дней было потрачено каждый разработчиком .NET для изучения C#/VB, базовой библиотеки и сопутствующих технологий? А сколько новых возможностей появляется, на которые опять нужно тратить ценные человеко-дни.
И это при том, что в Smalltalk с его неограниченными возможностями (объекты могут все и все является объектом — значит возможно все) на изучения языка уходит день, на стандартную библиотеку по ходу работы пару месяцев. И все — дальше ты начинаешь решать только насущные задачи, а сам язык не замечается абсолютно. Все очень прозрачно — вот мои классы и объекты, вот их сообщения. И то и другое хорошо ложится на проблемную область как участники системы и взаимодействие между ними.
Когда переходишь на Java, сразу чувствуется как наваливается множество ограничений, сильно снижающих продуктивность:
1. Почему new это какое-то ключевое слово, а не простой метод, и с ним ничего сделать нельзя?
2. Почему классы это не объекты, методы static нельзя переопределить и у них нет this?
3. Почему миллион в квадрате это полная билиберда?
4. Почему везде final?
5. Почему мне навязывают checked exceptions?
6. Почему во время отладки я не могу создать пару новых методов и подправить определение класса?
7. Почему обычный веб-сервер не может нормально работать 24x7 и его нельзя патчить на лету?
И так до бесконечности...
SM>
такие языки называются prototype-based; в них создание новых типов объектов осуществляется посредством клонирования имеющихся и внесения изменений непосредственно в структуру нового объекта
SM>То есть я в ответ на некое сообщение могу взять какой-то прототип, сделать с него копию и выкусить из копии пару полей или реакций на события? А какая мне от этого польза, ведь объекты, сконструированные на базе такого прототипа, не будут целостными? Ну, в плане добавления полей и реакций все вроде бы понятно. Непонятно только, зачем это делать при эксплуатации разработанной программы? Ведь возможные генерируемые таким образом прототипы все равно должны быть учтены при проектировании, а тогда их, вероятно, лучше описать заранее, чтобы не осложнять понимание программы? Иначе говоря, я опять же не вижу реальных преимуществ по сравнению, скажем, с Delphi и тем более с C# (C++ в расчет не беру только потому, что в языке отсутствует возможность конструирования объектов, класс которых на этапе компиляции неизвестен).
Ты конечно можешь выкусывать, но это не есть цель прототипов. Их цель исключить дуальный подход объект-класс, из-за которого в Smalltalk имеется нетривиальная структура объект-класс-метакласс и иерархии у них достаточно витиевато устроены.
При наличии прототипов создание новых экземпляров осуществляется сообщением copy, посланным прототипу (в случае с классами это сообщение new, посланное классу). Чтобы создать новый тип объектов, нужно взять какой-то прототип за основу, клонировать его, внести необходимые изменения и назвать его новым прототипом.
Таким образом объектная система упрощается, остаются только объекты, слоты и сообщения.
SM>
родительские слоты могут быть изменяемыми, т.е. поддерживается динамическое множественное наследование
Автор-то понимает, о чем сказал, а мне как быть? Что это означает и какие возможности открывает?
Упрощенно говоря — у каждого отдельно взятого объекта ты можешь менять его предков.
SM>Мне пока пришло на ум только одно потенциальное преимущество: можно использовать в своих откомпилированных разработках сторонние классы, неизвестные на момент компиляции. Хотя хранение метаданных часто само по себе позволяет решить эту задачу, даже в рамках "суженной" концепции ООП.
Не думаю, что это хорошо. Как раз выгоднее менять предков с заранее известным поведением. Таким образом легко реализуется паттерн State.
Т.е. если у нас есть объект Socket и у него состояния closed/connected/reading, тогда при смене состояния можно менять предка на SocketClosed/SocketConnected/SocketReading соответственно, который будет соответствующим образом обрабатывать все вызовы.
SM>Наконец, объясните мне, почему концепция вызова метода не может быть очень легко расширена до концепции посылки сообщения? В примитиве это вполне возможно даже в C, вспомним WinAPI SendMessage Если же сопроводить сообщение метаданными, описывающими передаваемую информацию и т.п., то разве концепции вызова метода будет недостаточно для воспроизведения операции посылки сообщения? Я не знаю, может быть, и нет.... Тогда, пожалуйста, объясните, в чем я ошибаюсь.
А по-твоему откуда SendMessage взялось?
Для наводки — message sending это концепция из Smalltalk, первый графический интерфейс создавался в Smalltalk и под него библиотека MVC, для элементов интерфейса была взята та же объектая метафора объектов и сообщений (каждый элемент представляется объектом, они обмениваются сообщениями)... Ход мысли понятен?
Посылка сообщения от вызова метода отличается двумя существенными моментами:
1. Любое сообщение можно послать любому объекту
2. Объект сам решает как ему обработать сообщение
Первое в Smalltalk выполняется автоматически, второе обеспечивается с помощью механизма #doesNotUnderstand:.
В принципе возможно приблизить по возможностям вызов метода к посылке сообщения. Что мы и видим в .NET на примере ContextBoundObject или RealProxy.
Но тут же возникает множество ограничений как раз связанных с крайней неоднородностью платформы. Т.е. все реализовано в виде каких-то специализированных случаев и использовать это не так то легко. А если что-то трудно использовать, то можно сказать, что этой возможности и нет. Мы же говорим не о принципиальной возможности что-то сделать, а о влиянии этой возможности на продуктивность.
Иначе всегда была бы актуальна фраза "да все это на ассемблере можно реализовать"...
SM>
SM>Теперь про скорость.
SM>Тот факт, что одни типы вызовов в статически типизированных языках выполняются значительно медленнее других, объявляется автором статьи недостатком этих языков. Довольно странно — я бы сказал, хорошо, что некоторые менее общие типы вызовов выполняются быстрее, чем более общие. Вряд ли можно назвать достоинством подхода его единообразно медленную работу на всех операциях.
Единообразно достаточно быструю.
Наличие быстрых, но тривиальных и медленных, но продвинутых возможностей волей-неволей подвигает людей отказывать от продвинутых в пользу быстрых.
Вот так и рождаются идеи типа "не используйте виртуальные методы, потому что они медленные"! И это говорят люди, пишущие приложения для баз данных. В домохозяйки — однозначно!
А если все — и продвинутые и простые операции не сильно отличаются по скорости, то даже и вопроса не возникает что использовать. Я ни разу не испытывал сомнений, если нужно было задействовать рефлекшн. Во-первых, потому что в Smalltalk он раз в сто быстрее, чем в Java, и к тому же профайлер не покажет там никакого узкого места, если там всего пару сотен вызовов.
SM>Врочем, далее автор опровергает мою сентенцию о единообразно медленной работе. Обратимся в слух:
SM>
Заметим, что посылка сообщения реализуется в динамических языках реализуется исключительно эффективно. По скорости она незначительно медленнее статического вызова. И, естественно, намного эффективнее виртуального вызова. (1)
Неплохо! Но в то же время: SM>
SM>Чем же таким особым обладает операция посылки сообщения (message passing), по сравнению с обычным вызовом метода (method invocation), который применяется в статически-типизированных языках?
SM>Для начала, стоит разобрать из каких этапов состоят эти две операции.
SM>И то, и другое имеет два основных этапа: поиск метода (method lookup) и собственно вызов метода (method invocation).
SM>Откуда видно, что все метод равно нужно искать. Виртуальный вызов метода требует всего одного дополнительного обращения к памяти по ср. со статическим. Что в таком случае может быть медленнее статического вызова, но значительно быстрее виртуального (1)?
Хитрость в кэшировании.
Смотри http://www.smalltalk.ru/articles/cpp-is-faster.html
SM>Кроме того, далее говорится о том, что в результате покупки динамического компилятора и его адаптации для Java удалось значительно ускорить работу Java-приложений. Вывод: Java-приложения работали медленно отнюдь не из-за ущербности Java по сравнению со Smalltalk или, в частности, из-за преимущества технологии посылки сообщений перед вызовом методов, а из-за меньшей эффективности компилятора и среды выполнения.
Правильно, дело не в этом. Дело в культуре разработки, которая прививается тем или иным подходом.
Smalltalk ориентируется на человека и его задачи, Java ориентируется на машину.
Поэтому полезные с точки зрения разработчика тяжелые операции — полиморфизм и рефлексия — получили высокий приоритет и были уравнены в правах с арифметическими операциями. Благодаря этому подходу и был создан "умный" компилятор, который хорошо управляется с полиморфными вызовами.
А в Java как всегда был сделан упор на тривиальные арифметические операции, а виртуальные вызовы реализованы классически по-тупому через таблицы методов и косвенные вызовы. Что на современных процессорах является ох какой дорогой операцией (но они тут умудряются "мухлевать" и запоминают несколько последних вызовах, но если вызовов с десяток, тут все и проседает).
SM>Slicer
_>Поэтому вот этот микро-цикл разработки является критичным (вспоминаю как мне приходится по десять минут перегрузать жававский веб-сервер ради малюсенького изменения). Объектный подход позволяет этот цикл сделать минимальным из возможных. Ты по ходу добавляешь код или корректируешь состояние объект чтобы увидеть как дальше оно работает.
Хм. В предположении, что на SmallTalk можно написать веб-сервер: при его отладке не понадобиться компилировать его заново для учета внесенных изменений?
_>Для примера — сообщение можно послать и числу, и вызовется соответветствующий метод. Или можно модифицировать посылку сообщений для объекта так, что они будут упаковываться и передаваться по сети. Таким образом мы получаем SOA, которая сейчас так рекламируется как замена ООП (а технически SOA оказалось всего лишь специализированной реализацией посылки сообщения — всего лишь одна треть ООП ).
Странно. В результате сегодняшнего обмена письмами с Ричардом Тёрнером у меня сложилось немного другое впечатление. А именно, что SOA не является заменой ООП, а лишь дополняет его в области, в которой требуется учет некоторых вещей, которые в чистом ООП не учтены. Впрочем, это к делу не относится, а относится вот что: ни пример с числом, ни пример с сетью не показывает, чем же посылка сообщения в корне отличается от вызова метода, и почему она выходит за рамки ООП в его обычном, не Алленовском понимании.
_>Однородность и предсказуемость решает. Она очень и очень упрощает разработку. Это не стоит игнорировать особенно учитывая человеческое 7+-2. _>Сколько человеко-дней было потрачено каждый разработчиком .NET для изучения C#/VB, базовой библиотеки и сопутствующих технологий? А сколько новых возможностей появляется, на которые опять нужно тратить ценные человеко-дни.
... _>Когда переходишь на Java, сразу чувствуется как наваливается множество ограничений, сильно снижающих продуктивность: _>1. Почему new это какое-то ключевое слово, а не простой метод, и с ним ничего сделать нельзя? _>2. Почему классы это не объекты, методы static нельзя переопределить и у них нет this? _>3. Почему миллион в квадрате это полная билиберда? _>4. Почему везде final? _>5. Почему мне навязывают checked exceptions? _>6. Почему во время отладки я не могу создать пару новых методов и подправить определение класса? _>7. Почему обычный веб-сервер не может нормально работать 24x7 и его нельзя патчить на лету? _>И так до бесконечности...
Ты же не хуже меня понимаешь, что почти все эти ограничения чем-то обоснованы: соображениями надежности программирования, или производительности, или и т.д. С ними можно соглашаться или не соглашаться, но они обоснованны. Кроме, разве что, того, что классы не являются полноценными объектами и нет метаклассов. И, честно говоря, я не вижу, как это может действительно снизить продуктивность работы. Впрочем, возможно, мне стоит попробовать пописать на SmallTalk
Но основная идея моего постинга заключалась не в защите Java или охаивании SmallTalk, а в том, что я не вижу, 1) почему подход SmallTalk не вписывается в "узкое" ООП, и 2) почему "узкое" ООП менее общо, чем подход SmallTalk.
А приведенные выше ограничения являются ограничениями языка, а не ООП.
_>Ты конечно можешь выкусывать, но это не есть цель прототипов. Их цель исключить дуальный подход объект-класс, из-за которого в Smalltalk имеется нетривиальная структура объект-класс-метакласс и иерархии у них достаточно витиевато устроены. _>При наличии прототипов создание новых экземпляров осуществляется сообщением copy, посланным прототипу (в случае с классами это сообщение new, посланное классу). Чтобы создать новый тип объектов, нужно взять какой-то прототип за основу, клонировать его, внести необходимые изменения и назвать его новым прототипом. _>Таким образом объектная система упрощается, остаются только объекты, слоты и сообщения.
То есть это не дает новых практически применимых возможностей, а лишь опять же служит унификации работы с различными сущностями языка, что предположительно (не спорю, может, это и так!) сильно повысит эффективность программирования. Я правильно понимаю?
_>Упрощенно говоря — у каждого отдельно взятого объекта ты можешь менять его предков.
Ясно. Но, как мне кажется, такая схема ничуть не лучше простого агрегирования Хотя... в отличие от агрегирования в "классических" языках, при этом сохраняется полиморфизм относительно типов-предков, так? Может, и применимо в некоторых случаях — так сразу ничего не приходит в голову.
_>Т.е. если у нас есть объект Socket и у него состояния closed/connected/reading, тогда при смене состояния можно менять предка на SocketClosed/SocketConnected/SocketReading соответственно, который будет соответствующим образом обрабатывать все вызовы.
Ну, тут вполне можно обойтись агрегированием обобщенного SocketImpl в класс-фасад Socket, а от SocketImpl отнаследовать SocketClosed/SocketConnected/SocketReading... Кстати, если я изменю предка с SocketClosed (фактически, пустышки) на SocketReading — состояние новоявленного предка мне придется инициализировать вручную?
_>А по-твоему откуда SendMessage взялось? _>Для наводки — message sending это концепция из Smalltalk, первый графический интерфейс создавался в Smalltalk и под него библиотека MVC, для элементов интерфейса была взята та же объектая метафора объектов и сообщений (каждый элемент представляется объектом, они обмениваются сообщениями)... Ход мысли понятен?
Ага, читал. Но заимствование концепции еще не делает заимствующего недееспособным
_>Посылка сообщения от вызова метода отличается двумя существенными моментами: _>1. Любое сообщение можно послать любому объекту _>2. Объект сам решает как ему обработать сообщение
Уже в Delphi существуют динамические методы с этими же двумя свойствами и механизм динамической диспетчеризации как альтернатива статической или виртуальной. Есть лишь одно ограничение, связанное с определенным уклоном в использовании этого механизма в Delphi: параметром динамически диспетчеризуемого метода должна быть структура не более чем определенного размера — 14 байт (тип значения не имеет), +2 заразервированных. Хотя можно создать свой диспетчеризатор (по-прежнему из одной функции!), который будет работать вместо этого с идентификатором сообщения и списком из произвольного числа произвольных параметров.
Про .NET я уже молчу
Ну, а если говорить о ООП... Как показывает пример Delphi, динамическая диспетчеризация легко выражается "один к одному" в понятиях "узкого" ООП, если язык предоставляет возможность свободно оперировать нестрого типизированными параметрами методов.
_>Но тут же возникает множество ограничений как раз связанных с крайней неоднородностью платформы. Т.е. все реализовано в виде каких-то специализированных случаев и использовать это не так то легко. А если что-то трудно использовать, то можно сказать, что этой возможности и нет.
Представим себе ситуацию, при которой механизм диспетчеризации Delphi изменен таким образом, как я только что описал. Чем же при таком подходе вызов диспетчера будет уступать посылке сообщения? А при наличии такой языковой поддержки (которая вообще не имеет отношения к ООП, так что правила игры не меняются) использовать динамическую диспетчеризацию будет совсем не трудно, а таки очень даже легко
SM>>Тот факт, что одни типы вызовов в статически типизированных языках выполняются значительно медленнее других, объявляется автором статьи недостатком этих языков. Довольно странно — я бы сказал, хорошо, что некоторые менее общие типы вызовов выполняются быстрее, чем более общие. Вряд ли можно назвать достоинством подхода его единообразно медленную работу на всех операциях.
_>Единообразно достаточно быструю. _>Хитрость в кэшировании. _>Смотри http://www.smalltalk.ru/articles/cpp-is-faster.html
Там ссылка на статью в PostScript, пока не читал, но обязательно почитаю. Пока мне приходит на ум только один способ заставить виртуальный вызов превратиться в статический: подменить адрес в точке вызова (назовем это привязкой). А при замене впоследствии объекта, которому направляется вызов, на другой, привязка отменяется и впоследствии может быть осуществлена снова, но уже к новому объекту. Любой другой способ потребует чтения адреса метода (раз он не указан в самой инструкции вызова ), так что, видимо, я угадал
Да, нельзя не согласиться.. Беру свои слова обратно, но лишь эти. А вот с тем, о чем я говорю дальше, спорить тяжело
_>Правильно, дело не в этом. Дело в культуре разработки, которая прививается тем или иным подходом. _>Smalltalk ориентируется на человека и его задачи, Java ориентируется на машину.
Все это очень замечательно. Но наша дискуссия так и не показала, почему практически важные возможности, предоставляемые "оригинальной" концепцией ООП вообще и Smalltalk в частности, шире, чем те, что возможны в рамках "суженной" концепции. Ну разве что фишка с динамическим наследованием...
Или я чего-то опять проглядел?
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
_>>Поэтому вот этот микро-цикл разработки является критичным (вспоминаю как мне приходится по десять минут перегрузать жававский веб-сервер ради малюсенького изменения). Объектный подход позволяет этот цикл сделать минимальным из возможных. Ты по ходу добавляешь код или корректируешь состояние объект чтобы увидеть как дальше оно работает. SM>Хм. В предположении, что на SmallTalk можно написать веб-сервер: при его отладке не понадобиться компилировать его заново для учета внесенных изменений?
Опять проглядывают уши процедурного подхода.
Объектную систему не нужно перекомпилировать. В ней изменения вносятся по одному методу. И если метод странслирован без ошибок, то создается объект-метод с байт-кодом, который помещается в словать методов, находящийся в объекте-классе. Естественно, изменения вступают в силу сразу же.
_>>Для примера — сообщение можно послать и числу, и вызовется соответветствующий метод. Или можно модифицировать посылку сообщений для объекта так, что они будут упаковываться и передаваться по сети. Таким образом мы получаем SOA, которая сейчас так рекламируется как замена ООП (а технически SOA оказалось всего лишь специализированной реализацией посылки сообщения — всего лишь одна треть ООП ). SM>Странно. В результате сегодняшнего обмена письмами с Ричардом Тёрнером у меня сложилось немного другое впечатление. А именно, что SOA не является заменой ООП, а лишь дополняет его в области, в которой требуется учет некоторых вещей, которые в чистом ООП не учтены. Впрочем, это к делу не относится, а относится вот что: ни пример с числом, ни пример с сетью не показывает, чем же посылка сообщения в корне отличается от вызова метода, и почему она выходит за рамки ООП в его обычном, не Алленовском понимании.
Транспортный уровень SOA реализуется через специализированную посылку сообщения из ООП. Поэтому да, SOA является некоторой специфической надстройкой ООП. Но в маркетинговых речах мы слышим нечто другое — ООП себя не оправдал, там нужно тащить длл-ки на сервер и при изменении публичного интерфейса в распределенном приложении приходится передеплоивать длл-ки; поэтому была придумана новая технология SOA, которая приходит на смену ООП, где сетевые сервисы обмениваются между собой сообщениями (loose binding так сказать).
Чувствуешь насколько описание SOA совпадает с объектным подходом? Но почему-то говорится, что "узкий" ООП не решает проблему? Т.е. авторы согласны с тем, что вызов процедуры послабее SOA будет, который в свою очередь идеально ложится на объекты и сообщения.
_>>Однородность и предсказуемость решает. Она очень и очень упрощает разработку. Это не стоит игнорировать особенно учитывая человеческое 7+-2. _>>Сколько человеко-дней было потрачено каждый разработчиком .NET для изучения C#/VB, базовой библиотеки и сопутствующих технологий? А сколько новых возможностей появляется, на которые опять нужно тратить ценные человеко-дни. SM>... _>>Когда переходишь на Java, сразу чувствуется как наваливается множество ограничений, сильно снижающих продуктивность: _>>1. Почему new это какое-то ключевое слово, а не простой метод, и с ним ничего сделать нельзя? _>>2. Почему классы это не объекты, методы static нельзя переопределить и у них нет this? _>>3. Почему миллион в квадрате это полная билиберда? _>>4. Почему везде final? _>>5. Почему мне навязывают checked exceptions? _>>6. Почему во время отладки я не могу создать пару новых методов и подправить определение класса? _>>7. Почему обычный веб-сервер не может нормально работать 24x7 и его нельзя патчить на лету? _>>И так до бесконечности... SM>Ты же не хуже меня понимаешь, что почти все эти ограничения чем-то обоснованы: соображениями надежности программирования, или производительности, или и т.д. С ними можно соглашаться или не соглашаться, но они обоснованны. Кроме, разве что, того, что классы не являются полноценными объектами и нет метаклассов. И, честно говоря, я не вижу, как это может действительно снизить продуктивность работы. Впрочем, возможно, мне стоит попробовать пописать на SmallTalk
Никогда абстрактные фабрики не писал? С объектным подходом затрат усилий на это — практически ноль.
Вот тебе и пример почему плохо, что классы не объекты.
Я вижу только два соображения для таких ограничений языка:
1. Если выкинуть объекты, должно получиться как в C — такие же возможности и такая же скорость.
2. Объектная часть должна быть реализована привычным образом.
Отсюда это наследие, местами очень глупое.
Опять попытка one size fits all. Но, как мы знаешь, это невозможно. Ниша возможностей и продуктивности Smalltalk точно не закрыта. А для голой скорости я использую C++. Поэтому и разработчик и машина остаются удовлетворены.
SM>Но основная идея моего постинга заключалась не в защите Java или охаивании SmallTalk, а в том, что я не вижу, 1) почему подход SmallTalk не вписывается в "узкое" ООП, и 2) почему "узкое" ООП менее общо, чем подход SmallTalk. SM>А приведенные выше ограничения являются ограничениями языка, а не ООП.
Ну почему же, последние два это как раз ограничения "узкого" ООП. Чтобы их снять, нужно будет сделать такие шаги, которые сильно приблизит его к чистому ООП или к чему-то эквивалентному (как Lisp например).
_>>Ты конечно можешь выкусывать, но это не есть цель прототипов. Их цель исключить дуальный подход объект-класс, из-за которого в Smalltalk имеется нетривиальная структура объект-класс-метакласс и иерархии у них достаточно витиевато устроены. _>>При наличии прототипов создание новых экземпляров осуществляется сообщением copy, посланным прототипу (в случае с классами это сообщение new, посланное классу). Чтобы создать новый тип объектов, нужно взять какой-то прототип за основу, клонировать его, внести необходимые изменения и назвать его новым прототипом. _>>Таким образом объектная система упрощается, остаются только объекты, слоты и сообщения. SM>То есть это не дает новых практически применимых возможностей, а лишь опять же служит унификации работы с различными сущностями языка, что предположительно (не спорю, может, это и так!) сильно повысит эффективность программирования. Я правильно понимаю?
Унификация и как результат новые возможности. Делегирование любому сообщений объекту, наличие нескольких предков, динамическое изменение предков и т.д.
Вот это передний край науки, а Smalltalk — это так, промышленная технология.
_>>Упрощенно говоря — у каждого отдельно взятого объекта ты можешь менять его предков. SM>Ясно. Но, как мне кажется, такая схема ничуть не лучше простого агрегирования Хотя... в отличие от агрегирования в "классических" языках, при этом сохраняется полиморфизм относительно типов-предков, так? Может, и применимо в некоторых случаях — так сразу ничего не приходит в голову.
Далеко не всегда нужно, но некоторые идиомы легко кладутся на код.
_>>Т.е. если у нас есть объект Socket и у него состояния closed/connected/reading, тогда при смене состояния можно менять предка на SocketClosed/SocketConnected/SocketReading соответственно, который будет соответствующим образом обрабатывать все вызовы. SM>Ну, тут вполне можно обойтись агрегированием обобщенного SocketImpl в класс-фасад Socket, а от SocketImpl отнаследовать SocketClosed/SocketConnected/SocketReading... Кстати, если я изменю предка с SocketClosed (фактически, пустышки) на SocketReading — состояние новоявленного предка мне придется инициализировать вручную?
У тебя прототип уже инициализирован. Но изменяя предка, ты конечно можешь вызвать у него любой метод дополнительной инициализации.
_>>А по-твоему откуда SendMessage взялось? _>>Для наводки — message sending это концепция из Smalltalk, первый графический интерфейс создавался в Smalltalk и под него библиотека MVC, для элементов интерфейса была взята та же объектая метафора объектов и сообщений (каждый элемент представляется объектом, они обмениваются сообщениями)... Ход мысли понятен? SM>Ага, читал. Но заимствование концепции еще не делает заимствующего недееспособным
_>>Посылка сообщения от вызова метода отличается двумя существенными моментами: _>>1. Любое сообщение можно послать любому объекту _>>2. Объект сам решает как ему обработать сообщение SM>Уже в Delphi существуют динамические методы с этими же двумя свойствами и механизм динамической диспетчеризации как альтернатива статической или виртуальной. Есть лишь одно ограничение, связанное с определенным уклоном в использовании этого механизма в Delphi: параметром динамически диспетчеризуемого метода должна быть структура не более чем определенного размера — 14 байт (тип значения не имеет), +2 заразервированных. Хотя можно создать свой диспетчеризатор (по-прежнему из одной функции!), который будет работать вместо этого с идентификатором сообщения и списком из произвольного числа произвольных параметров. SM>Про .NET я уже молчу SM>Ну, а если говорить о ООП... Как показывает пример Delphi, динамическая диспетчеризация легко выражается "один к одному" в понятиях "узкого" ООП, если язык предоставляет возможность свободно оперировать нестрого типизированными параметрами методов.
Опять же повторюсь, некоторые динамические возможности присутствуют во многих языках, но у них есть ряд серьезных ограничений (ты сам перечислил) и они не распространяются на все элементы языка. Т.е. использовать их будет посложнее, откуда и берется пресловутая разница в продуктивности.
К тому же когда динамические возможности не включены в базис языка, а реализваны как дополнительные фичи, то страдает все та же скорость.
А в объектной системе все является посылкой сообщения, поэтому она оптимизирована до безобразация. Поэтому разница скорости рефлекции и прокси отличается в сотни раз.
_>>Но тут же возникает множество ограничений как раз связанных с крайней неоднородностью платформы. Т.е. все реализовано в виде каких-то специализированных случаев и использовать это не так то легко. А если что-то трудно использовать, то можно сказать, что этой возможности и нет. SM>Представим себе ситуацию, при которой механизм диспетчеризации Delphi изменен таким образом, как я только что описал. Чем же при таком подходе вызов диспетчера будет уступать посылке сообщения? А при наличии такой языковой поддержки (которая вообще не имеет отношения к ООП, так что правила игры не меняются) использовать динамическую диспетчеризацию будет совсем не трудно, а таки очень даже легко
Разница в том, что для применения динамичекой диспетчеризации тебе нужно сделать усилие, потратить больше времени. И работать будет только в ограниченном числе случаев. И скорость пострадает. В общем одни неудобства.
SM>
SM>>>Тот факт, что одни типы вызовов в статически типизированных языках выполняются значительно медленнее других, объявляется автором статьи недостатком этих языков. Довольно странно — я бы сказал, хорошо, что некоторые менее общие типы вызовов выполняются быстрее, чем более общие. Вряд ли можно назвать достоинством подхода его единообразно медленную работу на всех операциях.
_>>Единообразно достаточно быструю. _>>Хитрость в кэшировании. _>>Смотри http://www.smalltalk.ru/articles/cpp-is-faster.html SM>Там ссылка на статью в PostScript, пока не читал, но обязательно почитаю. Пока мне приходит на ум только один способ заставить виртуальный вызов превратиться в статический: подменить адрес в точке вызова (назовем это привязкой). А при замене впоследствии объекта, которому направляется вызов, на другой, привязка отменяется и впоследствии может быть осуществлена снова, но уже к новому объекту. Любой другой способ потребует чтения адреса метода (раз он не указан в самой инструкции вызова ), так что, видимо, я угадал
Соображаешь.
Схема там, конечно посложнее, но общая идея такая.
SM>Да, нельзя не согласиться.. Беру свои слова обратно, но лишь эти. А вот с тем, о чем я говорю дальше, спорить тяжело
_>>Правильно, дело не в этом. Дело в культуре разработки, которая прививается тем или иным подходом. _>>Smalltalk ориентируется на человека и его задачи, Java ориентируется на машину.
SM>Все это очень замечательно. Но наша дискуссия так и не показала, почему практически важные возможности, предоставляемые "оригинальной" концепцией ООП вообще и Smalltalk в частности, шире, чем те, что возможны в рамках "суженной" концепции. Ну разве что фишка с динамическим наследованием... SM>Или я чего-то опять проглядел?
Так сколько раз уже обсуждали.
Не надо пытаться выискать какие-то теоретические преимущества. Все они заключены уже в самом определение.
Но главное не это — главное какую культуру разработки прививает тот или иной подход.
А благодаря объектному подходу появилось все то, что можно увидеть в Smalltalk — графический интерфейс, среда разработки, интерактивный отладчик, отсуствие цикла компиляции-запуска, бесперебойное исполнение, эволюционный дизайн, гибкие методологии, refactoring, SUnit, TDD, XP, ...
Этот момент хорошо ощущается после примыкания к соответствующей (любой) культуре разработки. Ты начинаешь руководствоваться соответствующими ценностями и производить сходный результат.
Например, примкнув к культуре Java я увидел JSP, необъектные beans, ненужное засилие XML и т.д. Встречаются и отличные вещи от Apache Group, но у меня ощущение, что плотность полезного намного меньше.
SM>Slicer
Здравствуйте, Vi2, Вы писали:
Vi2>Здравствуйте, Rumata, Вы писали:
Vi2>
R>>... Кто-то решил, что их должно быть 3, т.к. это "следует из инкапсуляции". Но, т.к. понятие самой инкапсуляции, как я понимаю, само четко не сформулировано, следствия из него имхо строить довольно опасно.
Vi2>Инкапсуляция — это доступность (или сокрытие) того, что имеет объект, для кого-либо, отличного от самого объекта.
Vi2>Количество состояний доступности определяется тремя словами "никому", "одному" и "всем". Если ты сможешь найти еще слово, которое не выражается из этих трех, то тебе будет слава и почет.
Мне кажется, что Rumata прав. Что в действительности значит public, private, protected?
Public в пределах чего? Модуля? Системы? Чего то ещё?
Private — для кого — класса, объекта, класса и его друзей, класса и друзей его друзей?
Protected — для класса и его потомков или только для объекта?
Разные языки трактуют это по разному, хотя большинство определяют идею инкапсуляции примерно одинакого...
Здравствуйте, Slicer [Mirkwood], Вы писали: SM>Уже в Delphi существуют динамические методы с этими же двумя свойствами и механизм динамической диспетчеризации как альтернатива статической или виртуальной. Есть лишь одно ограничение, связанное с определенным уклоном в использовании этого механизма в Delphi: параметром динамически диспетчеризуемого метода должна быть структура не более чем определенного размера — 14 байт (тип значения не имеет), +2 заразервированных. Хотя можно создать свой диспетчеризатор (по-прежнему из одной функции!), который будет работать вместо этого с идентификатором сообщения и списком из произвольного числа произвольных параметров.
Прошу прощения, а откуда дровишки про ограничения на параметры? Впервые об этом слышу.
... << RSDN@Home 1.1.4 beta 1 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AndreyFedotov, Вы писали:
AF> Мне кажется, что Rumata прав. Что в действительности значит public, private, protected? AF> Public в пределах чего? Модуля? Системы? Чего то ещё? AF> Private — для кого — класса, объекта, класса и его друзей, класса и друзей его друзей? AF> Protected — для класса и его потомков или только для объекта? AF> Разные языки трактуют это по разному, хотя большинство определяют идею инкапсуляции примерно одинакого...
Все очень и очень просто. Инкапсуляция в общем смысле — это ограничение прав внешних субъектов к данному объекту. В самом простом случае это вырождается в разделение между интерфейсом и реализацией. В юнитах Паскаля для этого есть две секции, которые совершенно четко выражают эту концепцию — interface и implementation.
Но структура Паскаля предполагает одноуровневые модули; никаких особых взаимоотношений между ними нет. Поэтому весь код делится только на две "кучи" — код моего модуля и код любого другого.
Как только появляется более сложная структура, появляется и желание более детально управлять обязанностями объекта. В привычном нам ООП (С++ и Object Pascal) объекты всегда можно поделить на три группы:
— объекты "моего" класса
— объекты классов — наследников
— все остальные объекты.
Именно из этих трех групп появились секции private, protected и public. Ребята, они не от бога даны. Это всего лишь отражение структуры конкретного языка. Не было бы наследования — не было бы protected.
Что мы наблюдаем в Java? Ага, помимо классов и наследования, появляются еще и пакеты. И сразу вводится четвертая категория доступа!
Кстати, в Delphi тоже есть лишняя (по отношению к С++) структурная единица — юнит. Было бы более чем логично ввести соответствующий спецификатор в язык для обозначения членов, доступных коду из того же юнита. Увы, разработчики языка не были готовы зайти так далеко, и вместо этого изменили смысл private. Т.е. на самом деле в Object Pascal нет private в смысле плюсов, хотя это не слишком и мешает.
Один взгляд в сторону дотнета подтвердит эти рассуждения с легкостью — появились сборки, и сразу потребовался спецификатор internal. Кстати, в отличие от канонической триады, internal и protected являются ортогональными. Т.е. мы не можем упорядочить все спецификаторы по "нарастанию открытости". Именно поэтому есть protected internal.
Помяните мои слова — при появлении в будущем более сложноструктурированных платформ список спецификаторов может быть расширен.
Представьте себе, что мы в .NET 3.0 решили выделить из всей массы посторонних классов те, которые живут в том же пространстве имен, и счесть, что наш класс будет иметь перед ними какие-то особые обязанности. Ок, введем спецификатор namespace. И возможные сочетания превратятся в:
S>Прошу прощения, а откуда дровишки про ограничения на параметры? Впервые об этом слышу.
Mea culpa
Сначала глючно написал, а потом не везде успел исправить.
Да, единственный var-параметр, тип не ограничивается
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Вот бука! Андрей,
А что делать? SM>так это ж не в языке В языке присутствует возможность дать пользователю это сделать, но сам язык ничего не знает об абстракных фабриках.
И я считаю что так и надо. ИМХО не нужно вносить в язык то что можно сделать не особо напрягаясь тремя десятками строк.
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Slicer [Mirkwood], Вы писали: SM>Да, единственный var-параметр, тип не ограничивается SM>Slicer
Странно. Никогда об этом не слышал. Дал себе труд проверить под D7. Следующий код прекрасно компилируется и работает:
type
TMyClass = class
public
procedure Test(a: string; b: integer; c: Extended); dynamic;
end;
TMyClass2 = class(TMyClass)
procedure Test(a: string; b: integer; c: Extended); override;
end;
По-моему кое-то путает диспетчеризацию вызовов через VMT/DMT с диспетчеризацией оконных сообщений.
... << RSDN@Home 1.1.4 beta 1 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Vi2, Вы писали:
Vi2>Здравствуйте, Rumata, Вы писали:
Vi2>
R>>А пока, как я понял, даже с терминологией не договорились.
Vi2>Интересно, есть ли определение точки, множества и т.п. терминов, краеугольные для математики? Которые вроде всем известны и понятны, но тем не менее...
Что касается теории множеств и парадоксов оной, то, как говорится, здесь скорее проблема не в понятии множества, а в самом слове "понятие". Вводя операции на множестве(суть, описание взаимодействия элементов множества) мы получаем структуры(полугруппы, группы, кольца и т.д.), которыми занимается алгебра. Операции, впрочем тоже являются элементами некоторого множества операций со своими операциями на нем Построение геометрии и теории функционального анализа невозможно без понимания топологии(в частности понятие предела определяется топологическими свойствами пространства). Математические дисциплины очень тесно взаимосвязаны друг с другом и одно немыслимо без другого.
P.S. Ну, а что касается точки — то это сильно зависит от контекста. Т.е. точка чего?
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Не, ты не понял SM>Не dynamic methods, a message methods!
Вот так и надо писать. А то
Уже в Delphi существуют динамические методы с этими же двумя свойствами и механизм динамической диспетчеризации как альтернатива статической или виртуальной
Вся фраза абсолютно верна по отношению к dynamic методам. А потом ты зачем-то съехал в описание ограничений совсем других методов.
... << RSDN@Home 1.1.4 beta 1 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
_>Чувствуешь насколько описание SOA совпадает с объектным подходом? Но почему-то говорится, что "узкий" ООП не решает проблему? Т.е. авторы согласны с тем, что вызов процедуры послабее SOA будет, который в свою очередь идеально ложится на объекты и сообщения.
А я поясню. Под ООП в данном случае в слоганах понимаются существующие реализации ООП — точнее, то, что вариантов межобъектного сетевого взаимодействия придумано множество. И SOA в числе прочего предлагает это сетевое взаимодействие стандартизовать (хотя сама парадигма SOA не предлагает такого стандарта, лишь призывает к его разработке).
_>Никогда абстрактные фабрики не писал? С объектным подходом затрат усилий на это — практически ноль.
Ну на Delphi на это вроде как особых усилий и не нужно, на то есть виртуальные конструкторы.
_>Ну почему же, последние два это как раз ограничения "узкого" ООП. Чтобы их снять, нужно будет сделать такие шаги, которые сильно приблизит его к чистому ООП или к чему-то эквивалентному (как Lisp например).
Почему же.. Среду разработки для любого языка с динамически компилируемыми методами и управляемыми объектами имхо можно усовершенствовать до такрого уровня. Сюда относится и Java, и любой .NET-язык. Действительно, что изменится, если мы добавим метод в класс или, тем более, изменим содержимое метода? Правда, некоторые трудности возможны с объектами на стеке в .NET (из-за изменения их размера при включении невиртуальных методов) и, возможно. с обновлением метаданных.
_>Опять же повторюсь, некоторые динамические возможности присутствуют во многих языках, но у них есть ряд серьезных ограничений (ты сам перечислил) и они не распространяются на все элементы языка. Т.е. использовать их будет посложнее, откуда и берется пресловутая разница в продуктивности. _>К тому же когда динамические возможности не включены в базис языка, а реализваны как дополнительные фичи, то страдает все та же скорость.
Но их можно включить в язык и можно снять большинство ограничений. И в этом случае вызов метода становится столь же мощным, как посылка сообщения. Я хочу сказать, что посылка сообщения не выходит за рамки "суженного" ООП.
_>Разница в том, что для применения динамичекой диспетчеризации тебе нужно сделать усилие, потратить больше времени. И работать будет только в ограниченном числе случаев. И скорость пострадает. В общем одни неудобства.
Опять же, посылка сообщения не выходит за рамки "суженного" ООП. Потому что при усовершенствовании только лишь процедурных возможностей языка посылка сообщения один к одному выражается вызовом метода.
SM>>Все это очень замечательно. Но наша дискуссия так и не показала, почему практически важные возможности, предоставляемые "оригинальной" концепцией ООП вообще и Smalltalk в частности, шире, чем те, что возможны в рамках "суженной" концепции. Ну разве что фишка с динамическим наследованием... SM>>Или я чего-то опять проглядел? _>Так сколько раз уже обсуждали. _>Не надо пытаться выискать какие-то теоретические преимущества. Все они заключены уже в самом определение. _>Но главное не это — главное какую культуру разработки прививает тот или иной подход. _>А благодаря объектному подходу появилось все то, что можно увидеть в Smalltalk — графический интерфейс, среда разработки, интерактивный отладчик, отсуствие цикла компиляции-запуска, бесперебойное исполнение, эволюционный дизайн, гибкие методологии, refactoring, SUnit, TDD, XP, ...
Иначе говоря, в настоящее время SmallTalk предоставляет некоторые возможности, отсутствующие в языках, построенных на базе "суженной" концепции ООП. Пускай, спорить с этим трудно.
Но это не означает, что "суженная" концепция проигрывает Алленовской в своей выразительной силе. Она лишь добавляет к Алленовской концепции несколько механизмов. Проектировщик может ими пользоваться, а может придумать свои, дополнительные. Но даже в этих условиях все рассмотренные нами задачи, решаемые Алленовским ООП, столь же легко решаются в рамках "суженного" ООП (я говорю об этапе проектирования, а не реализации — последняя ограничивается возможностями используемых языков).
Вроде бы, все выяснили
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Рррр. Message Methods являются динамическими методами, кроме того, они являются dynamic methods и управляются тем же внутренним механизмом, но программист сам приписывает им индекс метода.
А для обсуждаемой темы тонкости вроде того, как именно они называются в Delphi, значения не имеют: важно, что они существуют, что они могут служить для передачи сообщения и что для них используется динамическая диспетчеризация
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Иначе говоря, в настоящее время SmallTalk предоставляет некоторые возможности, отсутствующие в языках, построенных на базе "суженной" концепции ООП. Пускай, спорить с этим трудно. SM>Но это не означает, что "суженная" концепция проигрывает Алленовской в своей выразительной силе. Она лишь добавляет к Алленовской концепции несколько механизмов. Проектировщик может ими пользоваться, а может придумать свои, дополнительные. Но даже в этих условиях все рассмотренные нами задачи, решаемые Алленовским ООП, столь же легко решаются в рамках "суженного" ООП (я говорю об этапе проектирования, а не реализации — последняя ограничивается возможностями используемых языков).
Во первых "суженная" концепция сильно урезает ООП таким образом, что становится невозможным рекурсивный дизайн и эволюционно развивающаяся объектная система. Вдобавок приделанная (точнее оставленная) процедурная парадигма увеличивает энтропию. Получается плохо сопровождаемое нерегулярное ни то ни се.
Степень полиморфности вообще ограничивается только теми случаями, которые были явно предусмотрены. Т.е. там где программист поставил public/protected, virtual, нет final, создано побольше fine-grained интерфейсов и предусмотрена возможность повлиять на создание объектов.
В объектной среде пределов возможностям практически нет. Если выскочит баг в моей среде разработки, я тут же могу его сам пофиксить или обойти и продолжить выполнение функции дальше.
Продуктивность рождается только от дополнительных возможностей, а не от ограничений (сверх какого-то минимально необходимого набора).
SM>Вроде бы, все выяснили
Да, дальше что-то обсуждать уже будет излишне. Если твоей целью было получение точки зрения на проблему, то ты ее получил. Правда учти, что любая жесткая точка зрения есть добровольное самоограничение.
Лучшим способом изучить предмет по прежнему остается практическое использование. Правда тут есть своя опасность...
SM>Slicer
Здравствуйте, mihailik, Вы писали:
R>>Вот только опять не понятно, являются ли приведенные там документы какими-либо стандартами. неужели за более чем 10 лет развития, под ООП не подвели никаких признаных стандартов вообще?
M>А что, есть какие-то стандарты "реляционности" баз данных?
Да, нужно, чтобы любой запрос, сделанный на языке реляционный алгебры (есть такой), можно было переести на язык этой БД (SQL).
Здравствуйте, _vovin, Вы писали:
_>Именно так. Еще не придумано хороших математических методов описания задачи, когда исходный код можно создать сразу и правильно.
Э.Дейкстра. Дисциплина программирования.
Д.Грис. Наука программирования.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!