На досуге пытаюсь перечитывать книгу Гради Буча “Объектно-ориентированный анализ и проектирование”. Наткнулся на интересный фрагмент (раздел 1.3, курсивом выделена сноска и именно в ней все самое интересное):
Какая декомпозиция сложной системы правильнее - по алгоритмам или по объектам? В этом вопросе есть подвох, и правильный ответ на него: важны оба аспекта. Разделение по алгоритмам концентрирует внимание на порядке происходящих событий, а разделение по объектам придает особое значение агентам, которые являются либо объектами, либо субъектами действия. Однако мы не можем сконструировать сложную систему одновременно двумя способами, тем более, что эти способы по сути ортогональны [Лэнгдон предполагает, что эта ортогональность изучалась с древних времен. Он пишет: "К. X. Ваддингтон отметил, что такая дуальность взглядов прослеживается до древних греков. Пассивный взгляд предлагался Демокритом, который утверждал, что мир состоит из атомов. Эта позиция Демокрита ставила в центр всего материю. Классическим представителем другой стороны - активного взгляда - был Гераклит, который выделял понятие процесса"[Langdon, G. 1982. Computer Design. San Jose, CA: Computeach Press, p.6.]].
Она как! Истоки нужно искать еще в Древней Греции :)
Разделение по алгоритмам может и концентрирует внимание на порядке происходящих событий, однако функциональное программирование как раз (отсутствие побочных эффектов и ссылочная прозрачность) акцентирует внимание на том что порядок вычислений не важен, важнее декларативное описание, а в чистых ФЯ даже приходится идти на всякие ухищрения (CPS, монады) чтобы обеспечить нужный порядок вычислений.
ОтветитьУдалитьЗдесь, имхо, ты слишком акцентируешься на "порядке". Если же сделать водораздел на границе "процессов" (функций) и "атомов" (объектов), то все сходится.
ОтветитьУдалитьИмхо, алгоритм есть математическое понятие. Поэтому не нужно ставить равенство между алгоритмом и побочными эффектами.
Буч говорил о том, что щас называется процедурным программированием (а не ФП); ФП имеет некоторый уклон в сторону возникшего во времена эйлера 3-го взгляда на природу -- смотри например "принцип наименьшего действия"
ОтветитьУдалить@имя:
ОтветитьУдалитьна мой взгляд, между процедурным и функциональным подходом нет принципиальных отличий. На первом месте стоят действия по достижению конкретного результата (т.е. алгоритм). Различия только в количестве "разрешенных" побочных эффектов.
> Различия только в количестве "разрешенных" побочных эффектов.
ОтветитьУдалитьЭто только в том случае, если пытаться смешать функциональное и процедурное программирование (хотя это и перспективно и интересно); само же по себе ФП несет в себе совсем другую идеологию, принципиально несовместимую с *любыми* побочными эффектами (ПП) и изменениями состояния объекта (ООП) -- объект при своем изменении теряет identity.
Т.е. я в общем-то согласен с Рустамом.
>само же по себе ФП несет в себе совсем другую идеологию, принципиально несовместимую с *любыми* побочными эффектами
ОтветитьУдалитьИз-за этого "чистого ФП" в реальном программировании нет. Есть математика и есть программирование, в котором приходится считаться с массой вещей. В том числе и с наличием ПП. Причем, по сути, производство ПП и есть цель любой программы.
>изменениями состояния объекта (ООП) -- объект при своем изменении теряет identity
Для меня разница между ООП и процедурным/функциональным программированием заключается не в том, связаны ли объекты с изменениями и теряют ли объекты identity при модификации.
Разница заключается в подходе к проектированию. В ООП мы выделяем автономные сущности, от деталей которых мы можем на конкретном этапе абстрагироваться почти что полностью. И как раз в ООП проблема в том -- какими сущностями ограничиться, каким данными и операциями их снабдить, как выстроить их иерархии. И наложить все это на операции, которые программа должна выполнять.
Тогда как в ФП и процедурном подходе мы проектируем в рамках действий-функций.
> Причем, по сути, производство ПП и есть цель любой программы.
ОтветитьУдалитьНу это ты так считаешь, поскольку пишешь такие программы (вероятно для телекома).
А теоретики заметили, что такие программы вообще бывают, не очень давно, и даже, похоже не успели придумать к ним методы верификации (ирония).
Справедливости ради -- полно команднострочных утилит, которые работают как чистые функции, если считать, что им передаются файлы (а не строки).
> И как раз в ООП проблема в том -- какими сущностями ограничиться, каким данными и операциями их снабдить
бывает полезен взгляд "какими инвариантами их снабдить" (вместо операций), кстати его выдвигал Страуструп; он похожее более общий
> Тогда как в ФП и процедурном подходе мы проектируем в рамках действий-функций.
То, что ФП все же больше на тему функций, а не объектов, это однозначно. Интересно было бы подумать над аналогом ФП, но для объектов.
>Справедливости ради -- полно команднострочных утилит, которые работают как чистые функции, если считать, что им передаются файлы (а не строки).
ОтветитьУдалитьВ пределе и они не чистые -- они оставляют следы на консоли или в перенаправленном канале ввода-вывода. :)
недиалоговая программа, которая пишет в поток (терминал), и при этом не читает то, что было в этом потоке в прошлом (и в будущем :-), вполне может считаться программой без побочных эффектов; результатом работы такой программы будет tuple из выхлопов в отдельные файлы (включая терминал)
ОтветитьУдалить>результатом работы такой программы будет tuple из выхлопов в отдельные файлы (включая терминал)
ОтветитьУдалитьС учетом возможных ошибок ввода/вывода и блокировок программы при выводе (переполнение канала) -- не будет. :)
Абстрактная чистота не важна. Того что функциональные языки, даже нечистые (например тоже ML семейство) поощряют писать в функциональном стиле достаточно. Грязь и побочные эффекты изолируются основная масса кода при этом остается функциональной, уже это дает намного более надежный код. Ну и плюс конечно выразительность.
ОтветитьУдалить@Rustam: намного более надежный по сравнению с чем?
ОтветитьУдалитьПо-моему, даже Turbo Pascal с проверками на выход за пределы массивов и отсутствием адресной арифметики позволял делать намного более надежный код по сравнению с C++.
Намного более надежный код по сравнению с любым императивным языком. Кстати в C++ хоть const есть, но другие его недостатки его нейтрализуют.
ОтветитьУдалить>Намного более надежный код по сравнению с любым императивным языком.
ОтветитьУдалитьА за счет чего по-твоему?
За счет неизменяемых структур данных. В такой структуре на порядки меньшее число возможных состояний и соответственно возможностей допустить ошибку. Да даже тот же элементарный const в C++ уже прилично усиливает надежность.
ОтветитьУдалитьЗдесь http://fprog.ru/2009/issue1/eugene-kirpichov-fighting-mutable-state/ про мутабельность и ее недостатки неплохо написано.
>Здесь http://fprog.ru/2009/issue1/eugene-kirpichov-fighting-mutable-state/ про мутабельность и ее недостатки неплохо написано.
ОтветитьУдалитьНе понравилась мне эта статья. Во-первых, в начале статьи приведены примеры, которые показывают как все хреново с изменяемым состоянием. Но не показано затем, как все исправить с помощью неизменяемых состояний. В особенности интересно было бы про корзинку покупателя в магазине узнать.
Во-вторых, все эти проблемы более актуальны для языков с GC и с только ссылочными типами (вроде Java). Как ты правильно сказал, даже C++ const уже сильно меняет ситуацию.
Да примеры конечно не очень, но тема вполне раскрыта по моему.
ОтветитьУдалитьА C++ как всегда с одной стороны низкоуровневый с другой есть возможности просто недоступные в управляемых языках.