Где мне начинать использовать объекты, а где нет? Насколько это усложнит мою задачу (значительную часть времени я буду думать не о решении ее, а о там как получить нужные сущности)?
Если исходить из определения «объект — это изолированный процесс со своей областью памяти» и учитывая, что в ФП никакого shared state не бывает в принципе, то все ваши вопросы выглядят надуманными и на практике возникают исключительно редко. По крайней мере за год программирования на Elixir у меня ни разу не было дилеммы «что делать процессом, а что нет». Т.е. ни на сколько это не усложнит вашу задачу, исходя из практики — только упростит.
Как мне не-объекты превратить в объекты и наоборот (когда надо)?
Никогда не надо. Не бывает задачи превратить процесс в, допустим, список или наоборот — список в процесс.
Соответственно, речь таки не идет об ООП в исходном «Кэевском» смысле слова. Получается, скорее, некая имитация «антуража» ООП…
А он про то же самое говорит, что это один из двух путей понять «real OOP». По-моему тут явное противоречие Вашей точки зрения с точкой зрения Кэя.
показ интересных, нетривиальных задач с красивым ООП-решением
ну, это надо что-то из open source посмотреть, не писать же нетривиальный проект чисто в демо-целях )))
даже ваши коллеги по Erlang-у выражали сильное недоумение по поводу ООП-программирования на это языке.
Не забывайте, что имеет место сильная зашоренность на тему ООП. Для многих ООП == [«Инкапсуляция», «Наследование», «Полиморфизм»]. Для некоторых вообще ООП — это там где классы. В этом плане я согласен, с nwalker, когда говоришь ООП, никогда точно не знаешь, что подумал собеседник.
Примерно там же, где между API и его реализацией )))
Обработчик сообщения, в принципе, может обращаться к другим объектам, но не обязан. А когда вы запихиваете ООП на нижние уровни, то у вас и сообщения — это объекты, состоящие из объектов, и обработчик сообщений обязан работать с другими объектами. Вот именно в этот момент «всё есть объект» уничтожает базовые идеи ООП.
Согласен, у Вас есть такое же право на свою точку зрения. Просто меня удивляет, как Вы интерпретируя и опираясь на то, что пишет Кэй, приходите к несогласию с ним же. Я не говорю, что Elixir или Erlang лучше реализуют ООП, чем Smalltalk, это просто разные реализации. Идея в том, что все преимущества ООП можно использовать и в этих языках. При этом ещё и получив все преимущества ФП на уровне реализации.
Вот ещё Вам цитата из совсем свежего:
Что Вы ещё хотите понять про Erlang/Elixir в плане ООП, мне уже непонятно. Для полноценного сравнения со Smalltalk, если Вы его ждёте, мне пришлось бы освоить Smalltalk. Поэтому я сравниваю их с языками, которые мне уже хорошо известны, типа Ruby или C#. И они в плане соответствия идеям Кэя сильно проигрывают Elixir, хоть и достаточно полно (особенно Ruby) реализуют «Всё есть объект».
Вот, мне интересно, только честно: до наших с вами дискуссий вы много времени посвятили тому, чтобы вникнуть в суть ООП и его настоящие базовые идеи?
Достаточно много. Где-то 3 года назад заинтересовался истоками ООП.
ООП относится к верхнему уровню абстракции в системе, именно на этом уровне всё является объектом… Что там внутри объектов происходит ООП не описывает и не интересуется, потому что объект действует как чёрный ящик, принимающий и отсылающий сообщения. Всё! Дальше уже идут ненужные фантазии на тему ООП внутри объектов. Фантазий на эту тему достаточно много, но все они провальные и приводящие к усложнению простых вещей. И именно от них Алан постоянно пытается откреститься )))
Ну, able to — это не то же самое, что has to.
У Вас свои стойкие предубеждения и Вы интерпретируете всё в пользу Вашей точки зрения. Вплоть до того, что «initial premises in designing the Smalltalk interpreter» внезапно превращаются в определение ООП. И все, кто не согласен, с Вашей интерпретацией книги про раннюю историю Smalltalk, сразу признаются ничего не понимающими в ООП, похоже, включая и самого Алана )))
Вот его мнение от 2010 года в тему этой статьи:
Many of Carl Hewitt’s Actors ideas which got sparked by the original Smalltalk were more in the spirit of OOP than the subsequent Smalltalks. Significant parts of Erlang are more like a real OOP language than the current Smalltalk, and certainly the C based languages that have been painted with “OOP paint”.
А почему бы нет? На мой взгляд отличная реализация метафоры, которая легла в основу ООП:
biological scheme of protected universal cells interacting only through messages that could mimic any desired behavior
Тем более мейстрим-реализации ООП свели ценность этой аналогии к нулю, не обеспечивая реальную защиту внутреннего состояния и увлёкшись странной идеей, что ядро клетки — это тоже клетка, митохондрия — это тоже клетка, рибосома — тоже клетка и т.д… Но нет, внутреннее состояние клетки — это не набор других клеток. В биологии у вас не получится спуститься на уровень кварков и заявить, что кварк — это тоже клетка :-)
Зачем Вы спорите с очевидными вещами? То, что внутреннее состояние 1 равно 1, видно без каких-либо сообщений. То же самое с null, true и false.
Вообще идея и реализация — это всегда разные вещи. Реализация может демонстрировать идею, но не ограничивать. Да и есть цепляться за эти 6 пунктов, то они не выполняются вообще нигде, даже в Smalltalk:
Apparently, «everything isn't an object» afterall — some things are primitives.
Помогает тем, что с Integer-объектом я общаюсь ровно так же, как с любым другим объектом в системе — через сообщения.
Так а Integer-объект то зачем? Был у нас обычный всем понятный числовой литерал, а стал «объект», у которого внутреннее состояние выставлено наружу. Почему никто не пишет 1.getValue()? Почему возникают проблемы с boxing/unboxing? Потому что нет тут никакого единообразия. Потому что число — это число, а не объект. Вот и получается, что в теории хотели упростить, а на практике только усложнили.
ваше определение объектности не совпадает с Кэйевским — факт: убран первый пункт.
Насколько я понимаю, Вы ссылаетесь на Early History Of Smalltalk. Но там нигде не написано, что список идей для реализации интерпретаторов Smalltalk, является определением ООП. Не всё, что обязательно для Smalltalk, является обязательным для ООП. Иначе мы подменяем общую идею конкретной реализацией.
Почему не честно? На уровне архитектуры всё и остаётся объектами, а как там эти объекты внутри реализованы уже другой вопрос. Контрпродуктивным этот тезис стал, когда спустился на уровень примитивных типов и простых структур данных. Там он никогда простоте не служил.
Как Вам помогает в проектировании системы то, что 1 — это не 1, а экземпляр класса Integer с внутренним состоянием равным 1, к которому никто по идее не должен иметь доступ напрямую?
Да, всё верно. Предельно позднее связывание в действии :-)
Если Вы хотите, чтобы процесс не падал в таких ситуациях, можно определить catch-all обработчики сообщений, которые просто проигнорируют «левые» сообщения. Но с учётом того, что подобное может произойти только из-за ошибки/опечатки в коде, лучше пусть падает.
Я думаю, это в-первую очередь связано с тем, что Elixir поддерживает опциональные параметры.
Ну и как по мне, это логичнее, когда, допустим, функции для работы со списками принимают список в качестве первого аргумента, а не последнего.
Заметок о дизайне на эту тему я не встречал, но можно почитать в дискуссии в google-группе, например эту.
Вы неправильно поняли посыл статьи. Не надо всё делать объектами… Это ошибка проектирования. На нижнем уровне объекты только мешают, там гораздо удобнее работать с примитивными типами данных и структурами. В мейнстрим реализациях ООП начинается с идеи переноса объектов реального в программирование, а в итоге сводится к имитации, что строка общается с числами и т.п.
По поводу состояния, в Elixir оно надёжно спрятано в процессе, никакой рефлексией и уж тем более прямыми присваиваниями до него не достать. Только отправкой сообщений можно опосредованно влиять на состояние. Ну и как в любом функциональном языке все данные неизменяемы. Т.о. ситуация, когда вы получили часть состояния объекта по ссылке, передали в другой метод, а он взял его и изменил, тоже невозможны by design.
Процесс с этим pid упадёт с ошибкой типа (FunctionClauseError) no function clause matching in Airplane.handle_cast/2
airplane.ex:38: Airplane.handle_cast({:add, "Aimee", 2}, %{})
Вообще Erlang и Elixir стимулирует разработку по принципу «Let it crash». Поэтому чуть что не так — процесс падает и перезапускается с чистого листа одним из супервизоров.
Никогда не надо. Не бывает задачи превратить процесс в, допустим, список или наоборот — список в процесс.
А он про то же самое говорит, что это один из двух путей понять «real OOP». По-моему тут явное противоречие Вашей точки зрения с точкой зрения Кэя.
ну, это надо что-то из open source посмотреть, не писать же нетривиальный проект чисто в демо-целях )))
Не забывайте, что имеет место сильная зашоренность на тему ООП. Для многих ООП == [«Инкапсуляция», «Наследование», «Полиморфизм»]. Для некоторых вообще ООП — это там где классы. В этом плане я согласен, с nwalker, когда говоришь ООП, никогда точно не знаешь, что подумал собеседник.
Обработчик сообщения, в принципе, может обращаться к другим объектам, но не обязан. А когда вы запихиваете ООП на нижние уровни, то у вас и сообщения — это объекты, состоящие из объектов, и обработчик сообщений обязан работать с другими объектами. Вот именно в этот момент «всё есть объект» уничтожает базовые идеи ООП.
Вот ещё Вам цитата из совсем свежего:
Что Вы ещё хотите понять про Erlang/Elixir в плане ООП, мне уже непонятно. Для полноценного сравнения со Smalltalk, если Вы его ждёте, мне пришлось бы освоить Smalltalk. Поэтому я сравниваю их с языками, которые мне уже хорошо известны, типа Ruby или C#. И они в плане соответствия идеям Кэя сильно проигрывают Elixir, хоть и достаточно полно (особенно Ruby) реализуют «Всё есть объект».
Достаточно много. Где-то 3 года назад заинтересовался истоками ООП.
У Вас свои стойкие предубеждения и Вы интерпретируете всё в пользу Вашей точки зрения. Вплоть до того, что «initial premises in designing the Smalltalk interpreter» внезапно превращаются в определение ООП. И все, кто не согласен, с Вашей интерпретацией книги про раннюю историю Smalltalk, сразу признаются ничего не понимающими в ООП, похоже, включая и самого Алана )))
Вот его мнение от 2010 года в тему этой статьи:
пруф
Тем более мейстрим-реализации ООП свели ценность этой аналогии к нулю, не обеспечивая реальную защиту внутреннего состояния и увлёкшись странной идеей, что ядро клетки — это тоже клетка, митохондрия — это тоже клетка, рибосома — тоже клетка и т.д… Но нет, внутреннее состояние клетки — это не набор других клеток. В биологии у вас не получится спуститься на уровень кварков и заявить, что кварк — это тоже клетка :-)
Вообще идея и реализация — это всегда разные вещи. Реализация может демонстрировать идею, но не ограничивать. Да и есть цепляться за эти 6 пунктов, то они не выполняются вообще нигде, даже в Smalltalk:
© Heart Of Smalltalk
Ничто не ново под Луною…
Насколько я понимаю, Вы ссылаетесь на Early History Of Smalltalk. Но там нигде не написано, что список идей для реализации интерпретаторов Smalltalk, является определением ООП. Не всё, что обязательно для Smalltalk, является обязательным для ООП. Иначе мы подменяем общую идею конкретной реализацией.
Как Вам помогает в проектировании системы то, что 1 — это не 1, а экземпляр класса Integer с внутренним состоянием равным 1, к которому никто по идее не должен иметь доступ напрямую?
Если Вы хотите, чтобы процесс не падал в таких ситуациях, можно определить catch-all обработчики сообщений, которые просто проигнорируют «левые» сообщения. Но с учётом того, что подобное может произойти только из-за ошибки/опечатки в коде, лучше пусть падает.
Ну и как по мне, это логичнее, когда, допустим, функции для работы со списками принимают список в качестве первого аргумента, а не последнего.
Заметок о дизайне на эту тему я не встречал, но можно почитать в дискуссии в google-группе, например эту.
По поводу состояния, в Elixir оно надёжно спрятано в процессе, никакой рефлексией и уж тем более прямыми присваиваниями до него не достать. Только отправкой сообщений можно опосредованно влиять на состояние. Ну и как в любом функциональном языке все данные неизменяемы. Т.о. ситуация, когда вы получили часть состояния объекта по ссылке, передали в другой метод, а он взял его и изменил, тоже невозможны by design.
(FunctionClauseError) no function clause matching in Airplane.handle_cast/2
airplane.ex:38: Airplane.handle_cast({:add, "Aimee", 2}, %{})
Вообще Erlang и Elixir стимулирует разработку по принципу «Let it crash». Поэтому чуть что не так — процесс падает и перезапускается с чистого листа одним из супервизоров.
Полный текст интереснее.