Как стать автором
Обновить
2
0
gBear @gBear

Пользователь

Отправить сообщение

Имя метода обычно содержится в сообщении, в той или иной форме.

Это только если какой-то аналог RPC делается. Сообщение это данные. Обычно, если там и есть имя - это тип этих данных. Но ни как не тип потребителя этих данных. Тем более, что обработчик - вообще говоря - может быть и не один.

Достаточны только завтипы, и то не факт.

С одной стороны, хочется уточнить: достаточно для чего? А с другой - формализмы зав. типов - это "охренеть как смело" (с) :-)

Кроме того, вы так и не показали, что ваш формализм лучше.

Мой это какой?! Я - вроде как - никаких новых формализмов не вводил.

Примерно соответствующий (в вашей аналогии) сигнатуре метода в ООП

Каким образом?! Я ещё могу представить, как из "здоровенной схемы, описывающую сообщение" выводятся функциональные типы. Это не сложно. Но, что они вам дадут?! Что бы "выйти" на методы нам нужны имена. А тут они - буквально - любые.

Ну так оно и формализовано в большинстве языков, в виде интерфейсов...

Только на уровне формализма подтипа. Его - чаще всего - не достаточно. Поэтому там где нужных формализмов в языке нет, возникают всякого рода "техники программирования", которые переносят их (недостающие формализмы) на уровень реализации.

И в чём же разница-то, блин?

:-) Ну вот как это объяснить "на пальцах"?

Смотрите... вот у нас есть обычные типы (что бы это не значило). А есть функциональные типы. Какая между ними "разница"? Достаточно ли будет сказать, что функциональные имеют более высокий порядок? И в чём разница между типами разного порядка?

Или - с другой стороны заход - есть тип, а есть его экземпляры (что бы это не значило). Вот представьте себе эдакий НЕХ - экземплярами которого являются типы. Какая между ними разница? Мы на уровне типов даже выразить этот НЕХ (да... это про категорию типов) не сможем :-(

Т.е. эти вот "протоколы"/"поведения"/"классы типов" - это всё про "ограничения", которые накладываются не на уровне самих типов. Это про ограничения уровнем (я порой и не одним) выше, так сказать.

Когда вы реализуете "интерфейс", вы - фактически (через subtyping) - накладываете ограничения на [используемые] типы. С одной стороны, это вроде как "то, что нужно". А с другой - очень часто, это "не те" (либо слишком строгие, либо слишком слабые) ограничения, которые мы (на самом деле) хотим. По большому счету - это из-за того, что сам "интерфейс" - это тоже тип. Соответственно, он и описывается исключительно в "терминах" типов, со всеми их ограничениями. Даже если притащить сюда ещё и параметрический полиморфизм, то ограничения на параметры обобщенного типа - всё равно описываются в терминах типов. Не вырваться :-(

А если мы будет - по сути - тоже самое делать "уровнем выше", то никаких проблем такого рода у нас просто не будет.

Если идти дальше, то это уже какой-то "код" надо будет писать, чтобы показать "разницу". Оно надо?

Здоровенную схему, описывающую сообщение ...

Какой "объем знаний о получателе" это нам добавляет?

... плюс описание в документации, что этот получателе делать должен.

:-) А это точно нужно знать отправителю?!

Потому что если не знаем - то смысла посылать?

Например, потому что "что, куда и когда" определяется не отправителем (и не получателем), а протоколом. Точнее, контекстом, в котором сейчас находится отправитель, и протоколом, который этим самым контекстом задается.

Если вам удобнее смотреть на это (контекст и протокол) через призму "интерфейсов", то упрощенно это можно представить себе некоторый медиатор (в терминах GoF).

Так что знание таки всегда есть, пусть и не формализованное в языке.

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

Ну то есть, исключительно такие, в которых можно спросить компилятор "а это всё вообще имеет смысл?" ...

Если я правильно понял о чём речь, то "компилятор" - сам по себе - тут вообще не при чем. Статический анализ применим и к языкам с динамической типизацией. Главное, чтоб она (типизация) строгой была.

Но я-то не про типизацию... я про связывание (binding). Оно - вообще говоря - ортогонально типизации.

Не уверен что это преимущество.

На самом деле, это охренеть какое преимущество :-)

Всё же как программист вы обязаны знать хоть что-то о получателе ведь иначе с чего бы вам вообще пришло в голову посылать это сообщение?

Зачем?! Если "на пальцах": что вы "знаете" о получателе, когда отправляете сообщение, например, в какой-нибудь exchange AMQP брокера? Ну или, когда добавляете запись в какой-то topic kafka - вы много "знаете" о том, кто будет эту запись потом "читать"? А когда уже вы читаете запись и топика, вы что-либо "знаете" об "отправителе"? Зачем это вам?!

Кроме того, если такой свойство действительно необходимо - оно спокойно реализуется интерфейсами.

Ну, нет. "Интерфейсы" (а точнее, их реализация) - это просто "вот такая вот" форма subpyping'а. А protocol'ы smalltalk'а, behaviour 'ы erlang'а и прочая, и прочая - это не subtyping ни разу.

Я в одном, пожалуй, соглашусь... если рассматривать исключительно "статические" системы, то такого рода преимущество не совсем очевидно. Ну действительно - "зачем козе баян", если "всё, что может быть" мы и так уже описали "до того как".

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

Ну и чем же сообщения принципиально отличаются от методов-то?

Наверное тем, что для того, что послать сообщение получателю, про получателя не нужно знать вообще ничего?

Попробуйте посмотреть на ООП не как оно есть мейнстримно, а как оно было в оригинале - то, что Алан Кей сделал в Smalltalk.

Про "как" и "почему так", Алан "сделал в Smalltalk" лучше, имхо, почитать у самого Алана. Благо его The Early History of Smalltalk давно есть в сети. Очень познавательно.

Вот вам цитата. Это прям самое начало... даёт представление о "какую проблему решаем".

Though OOP came from many motivations, two were central. The large scale one was to find a better module scheme for complex systems involving hiding of details, and the small scale one was to find a more flexible version of assignment ...

Но лучше самому почитать, имхо. Там не много...

Т.е. посылка сообщений.

"посылка сообщений" - aka message passing - это то, что, в конечно счете, станет решением для этой самой "small scale one". То, что он сам потом назовет "extreme late binding of all things".

:-) Прям сразу "с козырей". Можно же было как-то "тихонечко"... через композицию там... подвести к теории типов... сумма типов, произведение... то сё... показать, что subclassing это такой "ugly kid Joe", в смысле суммы типов... ну и потому же - да - "шарахать" :-)

Сокрытие в ООП ни разу не является ключевым. Изначально оно про message passing, и никто не запрещает ввести сообщения, которые о состоянии расскажут.

Причем тут message passing?! Оно - не "цель" (ООП), а лишь инструмент (один из). Да и смысл "сокрытия" совсем не в том, что состояние не видно "из вне". А в том, что его (состояние) нельзя изменить "из вне".

Или вот Perl/Python - все поля объекта общедоступны, и ничего, это не перестает быть ООП.

"Открытое" состояние (и даже просто его принципиальная возможность в) - есть основная часть критики "оопешности" таких (и не только этих) языков/систем. Это, на всякий случай... вдруг вы не в курсе.

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

Как-то всё с ног на голову, имхо. Они - парадигмы т.е. - действительно про "одну цель". И DRY - если попытаться рассматривать этот принцип, как парадигму - тут не исключение. Цель эта - борьба со сложностью.

Если "маненько упростить", то ОПП - как парадигма - предлагает "сокрытие" состояния, как основной способ борьбы со сложностью (реализуемых систем). Т.е. вот прям буквально: если все изменения состояния S будут локализованы в S, то это не привнесет в систему (в которую S будет включено) сложность самой S. И в этом смысл. Речь - естественно - о "сложности системы" в инженерном смысле.

А дальше возникает, например, т.н. "позднее связывание" - как ответ на вопрос: "А как бы нам таки уже включить это самое S в нашу замечательную систему?" И т.з. целостности, его ("позднее связывание") тоже можно рассматривать (более того, так обычно и делают), как часть парадигмы ООП. Но важно понимать, что оно - не самоценно. И без первого ("сокрытия" состояния) - вообще говоря, имеет мало смысла в этой (ООП) парадигме. И, упомянутый вами, message passing - это как раз одни из способов (да, наверное самый универсальный, но таки один из) получить это самое "позднее связывание".

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

Я бы сказал - если "на пальцах" - причина: это мочь реализовывать/развивать более сложные системы, чем до этого. О "работе программиста" речь если и идет, то как о "третьей с конца по важности".

Открытость/закрытость - это слишком общие понятия.

Это вполне конкретные понятия. Их просто "нилюбют". Гораздо интереснее обсуждать "другое". Но, как только, обсуждение переводится хоть сколько-то академическую плоскость (из "научно-популярной") всё сводится к состоянию и его "открытости"/"закрытости". Иногда ещё говорят не о "закрытости", а о "локальности изменений" состояния - сути это не меняет.

Но куча не простая, в структурированная - данные связанны "смысловыми стрелочками" друг с другом и алгоритмами и алгоритмы друг с другом. Куча, море стрелочек!

"структурирование данных" и "куча стрелочек" (DF/CF и прочие F) - это СП. Оно очень даже допускает "открытое состояние". Более того - по большому счету - оно всё и построено вокруг "не локальности изменений" глобального состояния. Без этого оно просто "ниработаит" (tm).

И общая задача упорядочивания сводится к сокращению стрелочек и упрощению их структуры.

?!

Так что все принципы ООП важны.

Нет там никаких других "принципов". Точнее - они не имманентны "сокрытию состояния".

Ибо по отдельности они не достигают поставленной цели.

Цель - одна: скрыть состояние - т.е. "локализовать его изменения". Это сильно всё упрощает само по себе, знаете ли.

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

Извините, но как связаны "куча дублирующегося кода" и "наследование"? Точнее, как наличие второго исключает наличие первого? Или - по вашему - "наследование" - это про переиспользование чтоль?!

А наследование без полиморфизма - это вообще пытка над программистами из серии "протащи вызов через десять слоёв абстракции" (правда молодые программисты судя по моим наблюдениям её почему-то любят)

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

Точнее классы - это не ООП. Это вообще перпендикулярно. Но они очень сильно помогают дальнейшей метаструткуризации в ООП ...

Скажу так... есть гораздо более удобные способы для, чем subclassing.

Всегда удивляюсь, почему практически любое (читай, не академическое) обсуждение ООП всегда (и очень быстро) скатывается к обсуждению каких-либо технических деталей?

Концептуально, ООП это же очень просто: сокрытие состояния. Как говорится, какое из этих двух слов вам не понятно? :-)

Остальное всё (вот буквально - всё) - это средства, которыми это самое сокрытие достигается в том, или ином случае. Ну либо "следствия" их использования. Всё, от какого-нибудь message passing до, какого-нибудь subtyping - это всего лишь "инструменты", т.е. суть - вообще не важны для понимания.

Да даже само понятие "объект" - вторично. Внезапно, ООП замечательно обходится из без "объектов" - не говоря уже про, какие-нибудь "классы"... да и "типы" вообще :-)

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

Резюмируя... ООП - это не про "классы" и т.п. Когда мы говорим об ООП, то - по сути - мы говорим лишь от том, что "открытое" состояние - не допустимо. В отличие от какого-нибудь СП, которое вполне себе это допускает. Остальное уже частности, особенности платформ, конкретных языковых средств и т.п., которые - если убрать сокрытие состояния - тут же теряют всякую ценность.

Из этого же, например, следует, что "противопоставление" ООП и ФП - это немножко "такое" (tm). По отношению к наличию "открытого" состояния - они категоричны.

Да и ФП, которое, одновременно, ООП - это "вообще норм" (tm). В том смысле, что если есть (ну вот надо нам) состояние, то мы его обязательно скрываем. Например, в "процессе" - как в Erlang, или, например, в специальном "типе" - как в Haskell.

Как-то сильно "на пальцах" и, местами, вообще небрежно и - соответственно - порой, получается вообще "не про то" :-(

Начиная, с атомов (в примерах, внезапно, не "% примеры атомов"), и заканчивая "сумбуром" про функции, модули и процессы.

Как вообще можно рассказывать про Erlang, в котором - буквально - всё есть сопоставление с образцом... и из которого "прорастает" весь его синтаксис, начиная не с концепции "сопоставления с образцом"?!

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

Во-первых, "как что-то плохое" (tm) :-)
А во-вторых, что-то мы как-то не наблюдаем толпы тех, кто уже... что несколько печалит.

На данный момент, единственное, что мы - как исполнители - точно знаем: это то, что если "говнокод" и является проблемой, то это "проблема издержек". Со всеми вытекающими...

Статья, имхо, заход прям очень уже не с той стороны.

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

Грубо говоря, т.к. важен только наблюдаемый результат и больше ничего, то никто не готов платить за абстрактный "красивый код". Вот и всё.

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

Ну а то, что при достигнутом результате потом "главное, не трогать несущую трубу" (с) - вообще мало кого волнует. Да вообще никого, можно сказать :-)

Да-да-да :-)

"Выражение" - в смысле expression? Если да, то почему "подвыражение"? clause - с тем же успехом - и к statement (канон - внезапно - "оператор") может относится. Ну и оно вообще не про "под". Оно вполне себе самостоятельным может же быть. Да хоть уже упоминаемая function clause в erlang - это вполне себе самодостаточная языковая конструкция.

Но канона для clause в этом смысле - насколько я знаю - нет. Попытки есть... типа "предложение", "клаузула" и т.п. - но это, имхо, такое.

Эт хоть и не вам ответ был а для @sibirier, но таки спрошу: Таненбаума читали? Оба два? :-)

Но в текущий момент вся эта история тем не менее выглядит оторванной ...

Ну я чтоль виноват, что термин thread такой древний? :-) И к cpu - с его flow - он вообще не относился пол века почти. Он из "теории" операционных систем так-то.

Но цикл планировщика потоков (thread scheduler) - это и сейчас spin. Да и spin lock со spin wait'ом никуда не делись.

... и история с водяными потоками выглядит несколько более понятной.

Оно не правильно "выглядит". Эти ваши "водяные потоки" как-то можно ещё натянуть на те threads, что в cpu. А те, что в ОС - не "водяные", и не "потоки"... в том смысле, что их идея - как раз в обратном.

Слушайте... вот реально "и выросло поколение" :-) Без обид, только :-)

Изначально термин thread вообще к процессору (cpu) никакого отношение не имел. Это просто было лишено какого-либо смысла, ибо "там" - одни control flow и "вертись как хочешь". Thread - в изначальном смысле - это "часть" процесса (process) - который не "вообще" - а в некоторой операционной системе... которая тож не просто так... но эт не суть важно.

И вот ими (этими самыми thread'ами) управляет не cpu (он этого просто не умеет), а специальный планировщик (scheduler) - часть той самой "хитрой" ОС. Оно и сейчас, по большому счету, так.

Так вот - thread они потому, что scheduler... ну, он делает spin... вот - т.е. он буквально "прядет" их, переключая т.н. контекст исполнения :-) Control flow-то один.

Тут вот у нас "штука", которая делает spin, а это вот - значит - threads... всё логично :-)

И threads весьма долго и были "нитями" - тут без вариантов было (всёж логично - см. выше). А в "потоки" начали превращаться - если мне не изменяет память - с изданием у нас Таненбаума... т.е. в середине 90х примерно. И к 2000ым - на моей памяти - про "нити" уже никто (ну практически) не вспоминал. Т.е. threads стали "потоками" прям очень быстро... хотя, какой-нибудь spinWait никуда не делся (да он и сейчас - никуда не делся, впрочем), но никого это "не парило". И то, что "потоки" (это которые flow) уже были - никого не смутило, просто те "потоки" (flow) они у процессора, а эти "потоки" (которые thread) - они у ОС. И всё просто и понятно всем, кто в теме. Да и "семантически" они похожи - всё вообще шикарно. А то "нити" какие-то :-)

Как-то так, если "на пальцах".

А то, что потом и в cpu появились свои собственные threads - ну бывает. Оно так-то про "немножко другое"... но, "крякает, как утка..." - все дела. Все уже привыкли к тому, что "это" - threads.

P.S. Блин... это ответ был на верхнее сообщение топика. То, которое про "Изначальный перевод слова "thread" не очень удачный просто". Сорри - промахнулся.

Это в формализме любого языка есть. SQL тут не оригинален.

Конкретно я это перенял, если мне память не изменяет, у кого-то из Erlang'истов... как часть устойчивого выражения: "функциональная кляуза" :-)

Это про clause :-)
Expression, statement, clause и т.п... вот в этом контексте.

1
23 ...

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность