Здравствуйте, B0FEE664, Вы писали:
BFE>Не обязательно. Сообщение может быть таким: примени к себе следующий код: "<некоторый код для исполнения>". Например, message: eval, data: "alert('Hello World');".
Я имел ввиду такие штуки, как паттерн состояние. Там состояние имеют полный доступ к внутренним данным контекста. Контекст — объект, состояние — субъект.
Всё сказанное выше — личное мнение, если не указано обратное.
Здравствуйте, vaa, Вы писали:
vaa>Вот он говорит: vaa>
vaa>«Я жалею, что придумал термин «объекты» много лет назад,
vaa>потому что он заставляет людей концентрироваться на мелких идеях.
vaa>По-настоящему большая идея — это сообщения».
vaa>Разве объект не может быть сообщением? vaa>
vaa>set x = CreateObject("сообщение")
vaa>call послать x
vaa>
Может, более того, должен
vaa>Почему нельзя просто применить к данным функцию? vaa>
vaa>let r = hash "some data"
vaa>
Можно, но тогда мы теряем инкапсуляцию идентичность. А чтобы их ввести тебе понадобится еще одно понятие кроме данных и функций.
Ключевая идея Кея не в том, что есть объекты и сообщения, а в том что нет ничего кроме объектов и сообщений. Что все операторы (кроме передачи ссылки на объект) в языке можно свести obj.send(msg). Класс это тоже объект, метод класса — объект, стек вызовов и фреймы — тоже объекты. Большая часть SmallTalk написана на самом smalltalk.
А если смотреть глубже, то Кей под объектами имел ввиду что-то типа акторов, сведя таким образом к ООП в том числе асинхронное и параллельное программирование.
Кстати идея в общем неплохая оказалась, большинство динамических языков (Python и Ruby особенно) взяли очень многое от smalltalk.
Здравствуйте, Baiker, Вы писали:
B>Здравствуйте, vaa, Вы писали:
vaa>>Разве объект не может быть сообщением?
B>Может! И сообщением. И телеграммой. И ботинком. СЕЙЧАС ты зачем нам это всё рассказываешь? Ты считаешь, тут никто не знает про Смоллток?
Просто непонятно как это знание можно применить на практике.
Здравствуйте, Sinclair, Вы писали:
V>>Не обязательно. V>>Ящик может быть без состояния. S>Это частный случай более общей модели, в котором состояние ящика является пустым. В мире Кея решение иметь или не иметь состояние полностью отдаётся на откуп ящику. S>В частности, у чисел состояние есть, и оно неизменяемо. Но никаких средств выразить эту неизменяемость, как и само наличие либо отсутствие состояния, в Smalltalk нету.
Ес-но.
Как и в любом ООП-языке, предоставляющем ср-ва сокрытия внутреннего состояния.
S>>>Обмениваются они сообщениями. У сообщения в такой метафоре собственного поведения быть не может. V>>Но сообщение может содержать ссылку на другие ящики. S>Это никак не противоречит тому, что я написал.
Это отвечает на вопрос коллеги, которому ты отвечал — могут ли сообщения быть объектами?
Сообщения могут содержать отсылки к объектам.
ИМХО, засилье управляемых языков несколько атрофировало способность части коллег ощущать границу м/у объектами и ссылками на них.
V>>И если для ящика с состоянием принципиально, чтобы в сообщениях фигурировало лишь его ID, то объекты без состояний можно передавать по-значению, т.е. создавая копии их. V>>В этом моменте абтракция Кея недостаточно чётко отделяет мух от котлет. S>Да, конечно. Никто и не говорит, что абстракция Кея является непревосходимой вершиной архитектурной мысли.
Но она близка к законченной.
Не хватило буквально пары оговорок. ))
Хотя бы для того, чтобы эти оговорки десятилетиями не муссировали другие.
S>Современные мультипарадигменные языки безусловно удобнее смолтока для решения прикладных задач.
Смолтолк такой же мультипарадигменный, замыкания в нём описываются проще, чем в Common Lisp.
Я бы мог слегка поприкалываться и порассуждать на ту тему, что изначально мультипарадигменность не предполагалась, а она "получилась сама" в процессе доведения языка до уровня полезности, но я этого знать не могу. К тому же, язык разрабатывали несколько авторов, поэтому, упоротость одного из авторов не обязательно была определяющей — холодные головы инженеров-зануд порой вносят удачный баланс в качели мыслей инженеров-фантазёров. ))
Здравствуйте, σ, Вы писали:
V>>Ящик может быть без состояния. σ>Это называется тривиальный/вырожденный случай.
Но на этом история не заканчивается — ящик может содержать неизменяемое состояние, влияющее на его неизменяемое поведение, заданное при конструировании ящика.
Это тоже вырожденный случай?
Но на этом история опять не заканчивается — ящик может содержать неизменяемое "личное" состояние, но ссылаться на объекты с изменяемыми состояниями.
Слишком много вырожденных случаев, показывающих слабость первоначальной формулировки, не находишь? ))
Как сказал один известный Альберт: "Делай настолько просто, насколько это возможно, но не проще".
В общем, формулировку Кея нахожу неудовлетворительной/неполной.
В погоне за "перлом" сам себя обманул. ))
Здравствуйте, Философ, Вы писали:
Ф>, но в большинстве — нет, потому что тебе частенько нужно выполнить какой-то алгоритм над объектом. В таких случает объект является объектом, а не субъектом.
И в чем подвох? ))
ООП-абстракция не навязываей ролей в конкретном дизайне.
Разработчик сам решает какие сущности будут "активными", а какие "пассивными".
V>>>Ящик может быть без состояния. σ>>Это называется тривиальный/вырожденный случай.
V>Но на этом история не заканчивается — ящик может содержать неизменяемое состояние, влияющее на его неизменяемое поведение, заданное при конструировании ящика. V>Это тоже вырожденный случай?
Нет.
V>Но на этом история опять не заканчивается — ящик может содержать неизменяемое "личное" состояние, но ссылаться на объекты с изменяемыми состояниями.
Так. И?
V>Слишком много вырожденных случаев, показывающих слабость первоначальной формулировки, не находишь? ))
Здравствуйте, σ, Вы писали:
V>>Но на этом история не заканчивается — ящик может содержать неизменяемое состояние, влияющее на его неизменяемое поведение, заданное при конструировании ящика. V>>Это тоже вырожденный случай? σ>Нет.
С т.з. ваших рассуждений — да. ))
Если на некоторую формулу забиндили аргументы-константы, она не превращается от этого в объект с состоянием.
Простейший пример — биндинг лямбды к константам, в том числе частичный биндинг.
Вполне себе в духе Смолтолка.
V>>Но на этом история опять не заканчивается — ящик может содержать неизменяемое "личное" состояние, но ссылаться на объекты с изменяемыми состояниями. σ>Так. И?
И опять стирается грань м/у ящиком с состоянием и без.
V>>Слишком много вырожденных случаев, показывающих слабость первоначальной формулировки, не находишь? )) σ>Нет.
Я тебе уже пару подсказок выдал, а ты так и не смог провести очевидные границы различных сценариев (их 3 непересекающихся), покрываемых ООП-парадигмой, делающих эту парадигму мультипарадигменной by design. ))
Никакой из этих сценариев не является вырожденным, каждый из них является неотъемлимой частью ООП-подхода к проектированию, и тем более КОП-подхода.
"Вырожденными" эти сценарии кажутся только из-за неполноты формулировки Кея, о чём я и сделал замечание.
Здравствуйте, Sinclair, Вы писали:
4>>Поскольку Smalltalk полностью динамический, то Кей решил назвать "сообщением" — вызов метода, которого у объекта может не быть. S>Всё наоборот. Началось всё с сообщений, которые объект может обрабатывать по своему желанию. S>И уже из этой идеи стала вытекать полная динамичность смолтока.
Который, тем не менее, пригоден для статической компиляции, чем и занимается его JIT. ))
S>Поэтому нет никакой проблемы, скажем, отправить блок кода на исполнение удалённому объекту — как это сделано в СУБД GemStone.
Это следствие другого принятого решения — компиляции кода под архитектурно-независимую VM, т.е. оно перпендикулярно ООП-парадигме.
S>А также программным способом проинспектировать и поизменять программный код.
А это следствие еще одного решения — хранения метаинформации вместе с кодом.
S>Плюс там по аналогии с лиспом, которым Кей открыто вдохновлялся при проектировании смолтока, код существует в виде данных.
Если взглянуть внимательнее, то видно, что авторы более вдохновлялись Фортом (за авторством Чарльза Мура).
Сам Форт — это, по-сути, "бинарная" версия Лиспа, работающая эффективнее Лиспа порой на порядок.
Ну и, меньше скобок, больше синтаксиса, чище код.
Но "неестественная" запись осталась. ))
Плюс расплатой за эффективность стало явное оперирование состоянием стека (вернее, это был способ резко повысить эффективность на технике тех лет).
Смолтолк, считай, довёл цепочку Лисп-Форт-... до логической завершённости.
Заодно позволил обкатать ООП-парадигму, показать её эффективность.
(на Форте экспериментировали с "объектами" с самого начала)
В итоге ООП выиграло гонку популярности у ФП по очевидным причинам: ООП включало в себя целиком все известные на тот момент парадигмы — структурную и функциональную.
И если, скажем, ФП представляло из себя набор ограничений, то ООП представляло собой набор инструментария, в т.ч. для разработки другого инструментария, т.е. парадигма заведомо разрабатывалась для "расширения", а не ограничения. Первая человеческая IDE на Смолтолке с кучей функциональности (например, первый в мире автоматический рефакторинг) — самое яркое тому подтверждение. ))
Вдогонку, ООП-парадигма включила позже естественным образом даже модели из паралельных вычислений — модели акторов с мейлбоксами и модели конкурирующих сигналов.
Т.е. ООП-парадигма на сегодня является наиболее полной парадигмой из всех известных.
Взять даже наш давний спор об имутабельности vs const в С++.
Этот спор был изначально глуп с моей т.з., бо как можно сравнивать подмножество с полным множеством?
Через const в С++ можно выразить абсолютно все сценарии вокруг иммутабельности целиком, но это будет лишь небольшая вершинка айсберга всех сценариев, покрываемых const.
Зато наоборот — дудки. ))
И этот сомн остальных сценариев, выразимых через const, точно так же нужен и полезен.
И не только для защиты от дурака-программиста, но в т.ч. помогает компилятору генерить более оптимальный код, разрешает больше агрессии при оптимизации.
Здравствуйте, vdimas, Вы писали:
V>Но обратная польская запись осталась. )) V>Смолтолк, считай, довёл цепочку Лисп-Форт-... до логической завершённости. V>Заодно позволил обкатать ООП-парадигму, показать её эффективность. V>(на Форте экспериментировали с "объектами" с самого начала)
Вдогонку, на Форте синтаксис вызова методов объекта выглядит примерно так:
Здравствуйте, vaa, Вы писали:
vaa>Здравствуйте, Baiker, Вы писали:
B>>Здравствуйте, vaa, Вы писали:
vaa>>>Разве объект не может быть сообщением?
B>>Может! И сообщением. И телеграммой. И ботинком. СЕЙЧАС ты зачем нам это всё рассказываешь? Ты считаешь, тут никто не знает про Смоллток?
vaa>Просто непонятно как это знание можно применить на практике.
Smalltalk же! Написали язык в соотв. с теорией. Бери и пиши. Но т.к. эти концепции обосрались при проверке временем, крайне непонятно, зачем СЕЙЧАС подымать эту пыль. Мальчик познаёт мир?? Ну давайте теперь во всё тыкать, что ты прочёл — лисп, смоллток, рефал, оберон, пролог, оккмл... не надоело труху перебирать?
vaa>«Я жалею, что придумал термин «объекты» много лет назад,
vaa>потому что он заставляет людей концентрироваться на мелких идеях.
vaa>По-настоящему большая идея — это сообщения».
Заметим, что перед нами ни что иное, как граф активных сущностей ("процессов"), у каждого из которых есть вход и выход. То есть да, обменивающихся сообщениями.
Пример, однако, маргинален: граф всегда вырожден в цепочку, а "сообщения" нетипизированы.
Теперь рассмотрим какие-нибудь, например, диаграммы языка LabView:
Уже лучше: теперь и граф полноценный, и сообщения типизированные.
Однако, предметная область довольно узкая, языком общего назначения его точно не назовешь.
Думаю, Алан Кей в первую очередь имел в виду переход от ментальной концентрации на потоке управления к потоку данных.
В таком случае объекты становятся активными сущностями (каждый в своем процессе, потоке, либо замультиплексирован на основе event loop).
Здравствуйте, Философ, Вы писали:
Ф>Бредом это становится, когда начинаешь сам декомпозировать и распределять роли. Тут серьёзный подвох в том, кто именно выполняет действие: Ф>либо дверь открывается сама после подачи команды — смолтолк, либо кто-то дверь открывает.
Ну так это вы сами должны сначала решить, как это работает, а уже потом решение переводить в код.
Любой из вариантов возможен, this.open(door) и door.action(open). Какой из них правильнее — вопрос некорректный.
Например, если у героя могут быть 100500 способов открывания двери(ногой, рукой, рукой в перчатке, палкой, ключом, осторожно, рывком, итд) то стоит рассмотреть первый
Если же дверь просто открывается, без какой либо интриги, то стоит рассмотреть второй
И вы сами решаете, как ваши объекты взаимодействуют между собой — напрямую, или через посредника. Напрямую — первый вариант. Через посредника — второй.
На самом деле вариантов реализации в коде тоже 100500. Самое главное — что бы стоимость чтения-изменения-использования была минимальной, в т.ч. вашими коллегами.
Здравствуйте, vdimas, Вы писали:
V>Это следствие другого принятого решения — компиляции кода под архитектурно-независимую VM, т.е. оно перпендикулярно ООП-парадигме.
Нет, не следствие. Тот же Паскаль от рождения компилировал в платформенно-независимый P-код, и это никак не помогает ему в реализации подобных сценариев.
Да, перпендикулярно — в том же Лиспе никакого ООП нет, а вот code as data есть. Оттуда и слизано в SmallTalk.
И вообще к компиляции во что бы то ни было это отношения не имеет — в gemstone по проводу едет не "скомпилированный код", а его AST представление.
V>А это следствие еще одного решения — хранения метаинформации вместе с кодом.
Это всё одно и то же решение — code as data.
V>Сам Форт — это, по-сути, "бинарная" версия Лиспа, работающая эффективнее Лиспа порой на порядок. \
Ну, я в форте не спец, но особых сходств с Лиспом не вижу. V>Плюс расплатой за эффективность стало явное оперирование состоянием стека (вернее, это был способ резко повысить эффективность на технике тех лет).
Эмм, в Форте же вообще нет динамической памяти. Так что там нет ни неизменяемости, ни списков, ни сборки мусора, в общем, ничего из Лиспа в нём нет.
V>В итоге ООП выиграло гонку популярности у ФП по очевидным причинам: ООП включало в себя целиком все известные на тот момент парадигмы — структурную и функциональную. V>И если, скажем, ФП представляло из себя набор ограничений, то ООП представляло собой набор инструментария, в т.ч. для разработки другого инструментария, т.е. парадигма заведомо разрабатывалась для "расширения", а не ограничения. Первая человеческая IDE на Смолтолке с кучей функциональности (например, первый в мире автоматический рефакторинг) — самое яркое тому подтверждение. ))
И смолток так и остался уделом кучки гиков. А популярность ООП обрело только с выходом плюсов.
V>Вдогонку, ООП-парадигма включила позже естественным образом даже модели из паралельных вычислений — модели акторов с мейлбоксами и модели конкурирующих сигналов. V>Т.е. ООП-парадигма на сегодня является наиболее полной парадигмой из всех известных.
Это если смотреть на всё через призму ООП парадигмы. Скажем, Java на уровне 1.2 полностью реализует всю ООП парадигму.
Тем не менее, внезапно оказывается, что современное программирование не удовлетворяется одной лишь ООП парадигмой, и на рынке рулят мультипарадигменные языки, в которые проникли чисто-ФПшные штуки.
V>Через const в С++ можно выразить абсолютно все сценарии вокруг иммутабельности целиком, но это будет лишь небольшая вершинка айсберга всех сценариев, покрываемых const.
Напомните мне, как мне через const в c++ обеспечить неизменяемость аргумента, переданного мне в метод? Не запретить моему методу менять аргумент, а запретить внешнему коду менять мой аргумент?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
V>>Это следствие другого принятого решения — компиляции кода под архитектурно-независимую VM, т.е. оно перпендикулярно ООП-парадигме. S>Нет, не следствие. Тот же Паскаль от рождения компилировал в платформенно-независимый P-код, и это никак не помогает ему в реализации подобных сценариев.
Такой Паскаль лично я в руках не держал, держал Турбо-Паскаль, потом объектный, потом Дельфи.
Во внутренний P-код он компиллировался в память для отладки, чтобы исключить медленную на той технике стадию записи бинарного образа на диск и последующую его загрузку.
В любом случае, если даже такой Паскаль существовал (с возможностью сохранять и оперировать этим P-представлением), тогда и возможность соответствующая была.
Аргумент из разряда "было или нет реализовано" опять немного перпендикулярный.
Аналогично в VB — компиляция происходит в нейтив, но для отладки используется P-код в памяти, без сброса образа на диск.
S>И вообще к компиляции во что бы то ни было это отношения не имеет — в gemstone по проводу едет не "скомпилированный код", а его AST представление.
Что не требуется уже на уровне переносимых объектных файлов.
S>Да, перпендикулярно — в том же Лиспе никакого ООП нет, а вот code as data есть. Оттуда и слизано в SmallTalk.
Я уже говорил — из Форта, скорее, который являлся чем-то вроде бинарной версии Лиспа.
Натяжка Смолтолка на Лисп, таки, слишком смелая.
Зато на Форт прямая — под капотом была стековая VM с двумя стеками из Форта и такой же шитый код по результату работы JIT.
Это почему к эффективности Смолтолка были вопросы, из-за недостаточно умного JIT.
Зато PostScript, который является развитием Форта, вполне себе ездит с устройства на устройство и прекрасно исполняется.
V>>А это следствие еще одного решения — хранения метаинформации вместе с кодом. S>Это всё одно и то же решение — code as data.
Повторюсь, любой объектный файл (или архив их в объектной библиотеке) над переносимой платформой (например, llvm) представляет из себя то же самое.
Даже в Паскале, Си и С++.
К языку это перпендикулярно.
V>>Сам Форт — это, по-сути, "бинарная" версия Лиспа, работающая эффективнее Лиспа порой на порядок. S>Ну, я в форте не спец, но особых сходств с Лиспом не вижу.
Сходство с Лиспом там в общей схеме работы интерпретатора, который двухфазный:
1. компиляция во внутренее представление;
2. исполнение этого внутреннего представления.
Собсно, эти два языка отшлифовали принципы построения интерпретаторов, выделив их в отдельный класс ЯВУ.
В Форте была еще третья фаза — сохранение полученного скомпиллированного образа, в т.ч. одной из опций сохранения было удаление метаинформации ("словарей" в терминологии Форта) и неиспользуемых процедур ("слов" в терминологии Форта), т.е. запуск сохранённого образа затем сразу переходил ко второй фазе, т.е. не требовал текстовых исходников, что и определило поплярность Форта во встраиваемом оборудовании. Собсно, это был первый успешный язык достаточно высокого уровня, применённый во встраивемых сценариях. https://habr.com/ru/post/29967/
Далее сходство в организации контекста компиляции ("контекст" в терминах Лисп и "набор активных словарей" в терминах форта).
В Форте, в отличие от Лиспа, можно управлять "контекстом" явно.
В Лиспе только неявно.
Далее сходство в том, что код представляет из себя адреса символов и литералов.
Плюс в Форте численные литералы были представлены значениями, а не адресами.
Еще отличие Форта в том, что в коде хранится адрес исполняемой процедуры слова, в то время как в Лиспе хранился адрес метаинформации символа, т.е. Чарльз Мур убрал лишний уровень косвенности в процессе работы программы. Однако же, обратным поиском адреса в Форте запросто памятся на "слова". Т.е. Мур сделал размен эффективности оперирования метаинформацией на эффективность исполнения.
Посмотреть "код как данные" можно командой "see".
Любопытства ради выполни в любой онлайн Forth IDE программу:
see see
В отличие от большинства языков программирования, которые имеют жесткую структуру, не позволяющую изменять синтаксис и многие базовые элементы языка, ничто не мешает на Форте написать модификацию системы, понимающую синтаксис той предметной области, для которой пишется программа. Ярким примером является написание Форт-ассемблера для конкретного процессора, выполняемое за один рабочий день квалифицированным фортером.
Подтверждаю.
Задолго до выхода этой статьи в 1996-м я однажды плюнул на кривые ассемблеры под i35/i38/i48/i51 архитектуры и наваял кросс-ассемблер за один рабочий день.
Это вместе с макросистемой.
И сам ассемблер получился намного мощнее, т.к. изкаробки шла возможность описывать вычисления формул времени компиляции, офигенно помогало — достаточно было изменить одну константу (точное значение частоты кварца в моём случае) и все остальные константы можно было расчитать по достаточно сложным формулам прямо во время компиляции.
Да и, до первых виденных ЭВМ прилично упражнялся на программируемом калькуляторе MK-61, это тот же Форт, вид сборку.
Поэтому, программирование на Форте чуть позже зашло как к себе домой. ))
V>>Плюс расплатой за эффективность стало явное оперирование состоянием стека (вернее, это был способ резко повысить эффективность на технике тех лет). S>Эмм, в Форте же вообще нет динамической памяти.
Есть.
Оперирование динамической памятью явное.
Это самые базовые слова:
— "," — выделить ячейку в динамической памяти и скопировать туда значение с вершины стека;
— "@" — читать из памяти число адресу на вершине стека;
— "!" — писать число из второй ячейки стека по адресу на вершине стека.
Есть вариации шириной не только в слово, но и в полуслово, в байт, в двойное слово.
Со строками/массивами аналогично, копирование и т.д.
— "S=" — сравнение двух строк, заданных адресами на стеке и т.д.
— "-TH" — на стеке адрес массива и индекс, после исполнения на стеке элемент массива.
S>Так что там нет ни неизменяемости, ни списков, ни сборки мусора, в общем, ничего из Лиспа в нём нет.
В Форте можно описать произвольные структуры данных в памяти.
Сборка мусора в Лиспе, опять же, реализована по-разному.
В некоторых реализация сборка мусора вызывается каждый раз при исчерпании текущих свободных ячеек в предвыделенном пуле их, что может провоцировать (и провоцировала) сборку мусора даже когда потребности в этом не было, т.е. не было "забытых" объектов.
В других реализациях сборка мусора вызывается явно в рамках борьбы такими с холостыми срабатываниями.
В любом случае, с многопоточной сборкой мусора в современных VM этот подход имел мало общего.
Да и сборщик мусора консервативный, а не точный, как в Java или .Net.
Т.е. не перемещает данные (не уплотняет память).
Т.е., не помогла особо метаинформация.
Второй вариант без проблем может быть реализован в Форте на библиотечном уровне.
В Лиспе на библиотечном уровне никак, т.к. отсутствуют встроенные примитивы прямой работы с памятью и соотв. доступ ко внутренним кишкам интерпретатора.
(в кое-каких реализациях присутствуют, но это уже намного более поздние эксперименты в попытках привнести в Лисп свойства полее поздних ЯВУ общего назначения)
V>>В итоге ООП выиграло гонку популярности у ФП по очевидным причинам: ООП включало в себя целиком все известные на тот момент парадигмы — структурную и функциональную. V>>И если, скажем, ФП представляло из себя набор ограничений, то ООП представляло собой набор инструментария, в т.ч. для разработки другого инструментария, т.е. парадигма заведомо разрабатывалась для "расширения", а не ограничения. Первая человеческая IDE на Смолтолке с кучей функциональности (например, первый в мире автоматический рефакторинг) — самое яркое тому подтверждение. )) S>И смолток так и остался уделом кучки гиков. А популярность ООП обрело только с выходом плюсов.
С выходом объектного Паскаля и первых версий VB от MS, скорее.
А да, еще купленый и допиленный до Visual FoxPro (объектность там была на механике COM).
В те года С++ обитал в стадии "Си с классами" и точно был уделом гиков.
Плюсы были "распробованы" сообществом ближе к середине нулевых.
И во многом благодаря COM/OLE/ActiveX/MFC (а позже ATL) в Windows.
Наверно, нет смысла напоминать, что положение Windows и MS на тот момент можно было считать исключительным.
Вся отрасль тянулась за успехом их Windows и Офиса.
Оба продукта активно переписывались с Си на С++ в 90-е.
Даже драйвера устройств. ))
V>>Вдогонку, ООП-парадигма включила позже естественным образом даже модели из паралельных вычислений — модели акторов с мейлбоксами и модели конкурирующих сигналов. V>>Т.е. ООП-парадигма на сегодня является наиболее полной парадигмой из всех известных. S>Это если смотреть на всё через призму ООП парадигмы. Скажем, Java на уровне 1.2 полностью реализует всю ООП парадигму.
Java изначально ограничила саму ООП-парадигму и .Net совершила ту же ошибку в первоначальном дизайне.
И только сейчас пытаются залатать пробелы.
Помнишь обсуждение хотя бы новых управляемых указателей на методы в .Net?
А обсуждение типов-делегатов все нулевые года?
Надо ж было умудриться описать делегаты как объекты, что делегаты с одинаковой сигнатурой стали несовместимы. ))
Это серьёзный косяк, как ни крути.
C++ эту ошибку не совершал.
S>Тем не менее, внезапно оказывается, что современное программирование не удовлетворяется одной лишь ООП парадигмой, и на рынке рулят мультипарадигменные языки, в которые проникли чисто-ФПшные штуки.
Повторяю в сотый раз — "чисто ФП-шные" штуки были в ООП чуть не в первых ООП-языках.
Например, в том же Алголе-68.
Т.е. функциональный тип как первоклассный в языке, лямбды.
Симула, кстате, была тоже лишь попыткой объектного расширения Алгола.
Да и Смолтолк приобрёл свои характерные черты не в первой версии 72, и даже не в 76, а только в 80.
V>>Через const в С++ можно выразить абсолютно все сценарии вокруг иммутабельности целиком, но это будет лишь небольшая вершинка айсберга всех сценариев, покрываемых const. S>Напомните мне, как мне через const в c++ обеспечить неизменяемость аргумента, переданного мне в метод? Не запретить моему методу менять аргумент, а запретить внешнему коду менять мой аргумент?
Элементарно.
Для этого значение должно быть const в контексте внешнего кода.
Т.е. значение может быть const по всей иерархии "внешности", вплоть до объявления.
Или может приобретать признак const лишь с некоторой точки вычисления.
Это на выбор программиста.
Если начинать с момента объявления, то получаешь это:
Через const в С++ можно выразить абсолютно все сценарии вокруг иммутабельности целиком
Что будет лишь малой частью всех возможных сценариев по слишком очевидной причине (тут уже сложно не материться) — ввиду наиболее сильного наложенного на сценарий ограничения.
Странно, что мы вообще спорили тогда и сейчас вокруг подобной элементарщины...
Здравствуйте, vdimas, Вы писали:
V>Такой Паскаль лично я в руках не держал, держал Турбо-Паскаль, потом объектный, потом Дельфи.
RTFM: https://ru.wikipedia.org/wiki/P-%D0%BA%D0%BE%D0%B4 V>В любом случае, если даже такой Паскаль существовал (с возможностью сохранять и оперировать этим P-представлением), тогда и возможность соответствующая была. V>Аргумент из разряда "было или нет реализовано" опять немного перпендикулярный.
Простите, но это бред. V>Аналогично в VB — компиляция происходит в нейтив, но для отладки используется P-код в памяти, без сброса образа на диск.
Ну, так как мне воспользоваться этим кодом изнутри VB? V>Что не требуется уже на уровне переносимых объектных файлов.
При чём тут "не требуется"?
Речь о том, как что устроено, и с чем связаны какие возможности. V>Я уже говорил — из Форта, скорее, который являлся чем-то вроде бинарной версии Лиспа.
Продолжаете безудержно фантазировать. V>Натяжка Смолтолка на Лисп, таки, слишком смелая.
При чём тут натяжка? Это прямая речь Алана Кея.
V>Зато на Форт прямая — под капотом была стековая VM с двумя стеками из Форта и такой же шитый код по результату работы JIT.
Какой "такой же"? V>Это почему к эффективности Смолтолка были вопросы, из-за недостаточно умного JIT.
Опять пошёл какой-то бред. V>Зато PostScript, который является развитием Форта, вполне себе ездит с устройства на устройство и прекрасно исполняется.
А пост-скрипт то тут при чём? V>Повторюсь, любой объектный файл (или архив их в объектной библиотеке) над переносимой платформой (например, llvm) представляет из себя то же самое. V>Даже в Паскале, Си и С++. V>К языку это перпендикулярно.
Сколько бы раз вы ни повторяли, это не перестанет быть заблуждением.
Попробуйте реализовать на Паскале, Си, и С++ функцию, которая бы передавала пользовательский предикат на сервер для исполнения.
А потом для сравнения попробуйте реализовать то же самое на Lisp или SmallTalk.
Может быть, тогда до вас дойдёт, как такая возможность связана с языком.
V>Сходство с Лиспом там в общей схеме работы интерпретатора, который двухфазный: V>1. компиляция во внутренее представление; V>2. исполнение этого внутреннего представления.
С этой точки зрения более-менее похожи все языки, включая basic.
V>Еще отличие Форта в том, что в коде хранится адрес исполняемой процедуры слова, в то время как в Лиспе хранился адрес метаинформации символа, т.е. Чарльз Мур убрал лишний уровень косвенности в процессе работы программы. Однако же, обратным поиском адреса в Форте запросто памятся на "слова". Т.е. Мур сделал размен эффективности оперирования метаинформацией на эффективность исполнения.
Короче, общего примерно столько же, сколько у вороны с роялем.
V>Да и, до первых виденных ЭВМ прилично упражнялся на программируемом калькуляторе MK-61, это тот же Форт, вид сборку. V>Поэтому, программирование на Форте чуть позже зашло как к себе домой. ))
Простите, но рассуждения про Форт не очень интересны в контексте ООП. А ваше очередное самолюбование не интересно совсем.
V>Оперирование динамической памятью явное. V>Это самые базовые слова: V>- "," — выделить ячейку в динамической памяти и скопировать туда значение с вершины стека; V>- "@" — читать из памяти число адресу на вершине стека; V>- "!" — писать число из второй ячейки стека по адресу на вершине стека.
Это, мягко говоря, совсем не то, что применяется в Лиспе или Смоллтоке.
V>В Форте можно описать произвольные структуры данных в памяти.
В ассемблере тоже. Это не делает ассемблер лиспоподобным языком.
V>Сборка мусора в Лиспе, опять же, реализована по-разному.
Это подробности. Она является неотъемлемой частью языка.
V>В некоторых реализация сборка мусора вызывается каждый раз при исчерпании текущих свободных ячеек в предвыделенном пуле их, что может провоцировать (и провоцировала) сборку мусора даже когда потребности в этом не было, т.е. не было "забытых" объектов. V>В других реализациях сборка мусора вызывается явно в рамках борьбы такими с холостыми срабатываниями.
Чегось? V>В любом случае, с многопоточной сборкой мусора в современных VM этот подход имел мало общего.
Это вообще иррелевантно к данному обсуждению. Речь о языке, а не о реализации. V>Да и сборщик мусора консервативный, а не точный, как в Java или .Net. V>Т.е. не перемещает данные (не уплотняет память).
Чегось? Продолжается безудержный бред, да? V>Т.е., не помогла особо метаинформация.
Прекрасно помогла.
V>Второй вариант без проблем может быть реализован в Форте на библиотечном уровне. V>В Лиспе на библиотечном уровне никак, т.к. отсутствуют встроенные примитивы прямой работы с памятью и соотв. доступ ко внутренним кишкам интерпретатора. V>(в кое-каких реализациях присутствуют, но это уже намного более поздние эксперименты в попытках привнести в Лисп свойства полее поздних ЯВУ общего назначения)
В лиспе сборка мусора является частью языка. Отсутствие примитивов прямой работы с памятью — это скорее плюс, чем минус.
V>С выходом объектного Паскаля и первых версий VB от MS, скорее.
Это в (бывшем) СССР. А в мире объектные версии Паскаля прошли практически незамеченными массовой публикой.
Попробуйте найти литературу по ООП с примерами на Паскале или VB.
V>Java изначально ограничила саму ООП-парадигму и .Net совершила ту же ошибку в первоначальном дизайне.
Мне даже интересно, какие именно аспекты ООП-парадигмы проигнорировала Java. V>Помнишь обсуждение хотя бы новых управляемых указателей на методы в .Net? V>А обсуждение типов-делегатов все нулевые года? V>Надо ж было умудриться описать делегаты как объекты, что делегаты с одинаковой сигнатурой стали несовместимы. ))
Это, собственно, и есть попытки выйти за пределы ООП-парадигмы. В чистом ООП никаких делегатов нет. Есть интерфейсы с определёнными сигнатурами.
А несовместимость делегатов с одинаковой сигнатурой в рамках ООП не является самостоятельной особенностью. Она скорее связана с выбором между утиной типизацией и номинативной типизацией. V>Это серьёзный косяк, как ни крути. V>C++ эту ошибку не совершал.
Скажем, в С++ два одноимённых типа с "одинаковой сигнатурой" ничуть не более совместимы между собой, чем в дотнете.
Это в ФП подобные проблемы возникнуть не могут, т.к. там совместимость любых функций с одинаковой сигнатурой ставится во главу угла. А в лиспе так и вообще, одинаковость сигнатуры не является критерием.
V>Повторяю в сотый раз — "чисто ФП-шные" штуки были в ООП чуть не в первых ООП-языках. V>Например, в том же Алголе-68. V>Т.е. функциональный тип как первоклассный в языке, лямбды.
Мне кажется, вы слишком смело называете Алгол ООП-языком. Никакого ООП в нём не было. V>Симула, кстате, была тоже лишь попыткой объектного расширения Алгола.
Как так — взяли ООП-шный алгол и попробовали привинтить к нему "объектное расширения"? V>Да и Смолтолк приобрёл свои характерные черты не в первой версии 72, и даже не в 76, а только в 80.
:sigh: http://wiki.c2.com/?AlanKaysDefinitionOfObjectOriented
V>Для этого значение должно быть const в контексте внешнего кода.
Не-не-не, Дэвид Блейн. Вот я пишу свой код. И в нём мне бы хотелось полагаться на то, что его вызывают не с чем попало, а с неизменяемым объектом. V>Т.е. значение может быть const по всей иерархии "внешности", вплоть до объявления.
Внешний код ещё не написан — каким образом я смогу потребовать от него const на этом значении "по всей иерархии внешности"?
V>Это на выбор программиста.
V>Что будет лишь малой частью всех возможных сценариев по слишком очевидной причине (тут уже сложно не материться) — ввиду наиболее сильного наложенного на сценарий ограничения.
Ок, как видим, вы так и не поняли, что такое иммутабельность, и почему она ортогональна const. V>Странно, что мы вообще спорили тогда и сейчас вокруг подобной элементарщины...
Да ничего странного — у вас отсутствует обучаемость. Годы идут, а вы так и не вышли за пределы своих заблуждений.
В качестве упражнения можете попробовать спроектировать на С++ пару абстрактных классов — изменяемый вектор и immutable вектор. В терминах дотнета это были бы IImmutableList<T> и IList<T>. И посмотрите, можно ли их отнаследовать друг от друга; можно ли получить один из другого при помощи модификатора const; понадобится ли вообще модификатор const при проектировании этих классов или при их использовании.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
RTFM чего именно?
Что такое P-код? ))
Это тоже перпендикулярно языку.
Собсно, по твоей ссылке и говорится, что концепция была впервые реализована в другом языке.
Сам я впервые "вживую" курочил P-код в Бейсике ZX Spectrum.
Паскаль под ZX Spectrum компилял в нейтив.
Паскали под IBM PC ходили борландовый и от MS, в P-код не компиллировали.
V>>В любом случае, если даже такой Паскаль существовал (с возможностью сохранять и оперировать этим P-представлением), тогда и возможность соответствующая была. V>>Аргумент из разряда "было или нет реализовано" опять немного перпендикулярный. S>Простите, но это бред.
Медитировать до просветления, как грится.
Сам же привёл пример конкретной системы gemstone, т.е. имелась ввиду соответствующая инфраструктура в этой системе.
V>>Аналогично в VB — компиляция происходит в нейтив, но для отладки используется P-код в памяти, без сброса образа на диск. S>Ну, так как мне воспользоваться этим кодом изнутри VB?
Языками более низкого уровня.
Или расписать некий фреймворк оперирования памятью в некоей библиотеке и сделать импорт функций в VB (есть такая возможность), чтобы иметь требуемый инструментарий.
Например, можно взять готовую либу CRT.
V>>Что не требуется уже на уровне переносимых объектных файлов. S>При чём тут "не требуется"?
Потому что в объектных файлах содержится код и данные со всей сопутствующей метаинформацией.
S>Речь о том, как что устроено, и с чем связаны какие возможности.
Если требуется посылать код другому устройству, то требуется переносимость кода.
Я уже начинаю подозревать, что ты видишь возможность переносимости кода только в виде его AST-представления.
В то время как исторически переносимость обеспечивалась P-кодом, хотя он изначально и не назывался так, а назывался кодом для абстрактной машины.
Кнут тоже использовал абстрактную машину в своих "Искусствах программирования" (если ты читал эти труды).
У нас был коллективный курсовик на 3-м курсе на тему реализации абстрактной машины и минимальной операционки+компилятора для него.
В общем, твоя попытка рассуждать о банальностях как об откровениях малость сбивает меня с толку. ))
V>>Я уже говорил — из Форта, скорее, который являлся чем-то вроде бинарной версии Лиспа. S>Продолжаете безудержно фантазировать.
Провожу ликбез.
V>>Натяжка Смолтолка на Лисп, таки, слишком смелая. S>При чём тут натяжка? Это прямая речь Алана Кея.
Хосподя, Алан Кей тот еще болтун, навроде тебя.
Причём, болтуном он стал гораздо позже... в попытках, не знаю, придать некую публичную окраску своей роли в этой работе.
Он работал над этой системой не один, слава богу.
Такие монстры как Голдберг служили неплохим противовесом этому, в общем-то, нубу-самоучке.
Изначально Смолтолк был попыткой описать схематику Симулы на основе того ограничения, что "объекты" обмениваются лишь "сообщениями".
Какой там в опу Лисп? ))
Система получилась убогой по быстродействию, поэтому была переработана унутре на манер Форта.
Просто ты не знаешь (или не понимаешь) о чём речь.
Похоже, ты не трогал толком ни Смолтолк, ни Лисп, ни Форт, не понимаешь внутренней механики этих языков, но пытаешься фантазировать.
Рассуждать о Лиспе можно было лишь в последней версии Смолтолка-80, когда добавили метаклассы.
ООП в виде CLOS привнесли в 70-х в виде стандарта, напомню, и это всего лишь эмуляция ООП на библиотечном уровне.
Но концепции обкатывались, не без этого.
Т.е. в изначальном Лиспе никаких метаклассов не было, как и не было в Лиспе ООП, ес-но, были только ф-ии как первоклассные объекты (сам код) и данные в виде однонаправленно связанных встроенных в систему списков.
Очередное твоё "слышал звон".
Просто ссылаться на Лисп однажды стало модно, бгг, и этот болтун не преминул.
V>>Зато на Форт прямая — под капотом была стековая VM с двумя стеками из Форта и такой же шитый код по результату работы JIT. S>Какой "такой же"?
Курить, что есть шитый код.
V>>Это почему к эффективности Смолтолка были вопросы, из-за недостаточно умного JIT. S>Опять пошёл какой-то бред.
Ликбез.
V>>Зато PostScript, который является развитием Форта, вполне себе ездит с устройства на устройство и прекрасно исполняется. S>А пост-скрипт то тут при чём?
Пример развития Форта до переносимости м/у устройствами.
Наглядно показывает, что "переносимость" не берется из воздуха.
Что требует для своей реализации как некие св-ва вычислительной модели, так и заточенную под переносимость обвязку (инфраструктуру).
Это, блин, просто пример, хотя бы немного воткнув в который, ты бы избавился от многих своих дурацких вопросов и еще более дурацких попыток спора по элементарным вещам.
Таки, самообразованием принято заниматься самостоятельно, не испытывая терпение коллег.
V>>Повторюсь, любой объектный файл (или архив их в объектной библиотеке) над переносимой платформой (например, llvm) представляет из себя то же самое. V>>Даже в Паскале, Си и С++. V>>К языку это перпендикулярно. S>Сколько бы раз вы ни повторяли, это не перестанет быть заблуждением.
Но доказать не сможешь? ))
S>Попробуйте реализовать на Паскале, Си, и С++ функцию, которая бы передавала пользовательский предикат на сервер для исполнения.
Не вижу технических проблем передать чистую ф-ию или чистое замыкание при наличии соотв. инфраструктуры.
В вопросе удалённого исполнения кода есть всего два требования:
— переносимость кода;
— переносимость данных.
Переносимость данных была реализована в рамках COM/OLE и CORBA.
Переносимость кода и вообще отправка на удалённое исполнение в рамках ActiveX-апплетов (но только в рамках одной архитектуры).
Более широкая переносимость кода была реализована в тех же Java-апплетах и .Net-апплетах.
Напомню, что MS компилятор С++ умеет компиллировать unamanaged C++ код (т.е. безо-всяких managed расширений) в чистый байт-код.
(тип генерируемого образа для режима С++/CLI задаётся опциями компилятора)
S>А потом для сравнения попробуйте реализовать то же самое на Lisp или SmallTalk.
Ну вот попробуй на Лисп (или другом динамическом языке) без динамического исполнения текстовых исходников, а я поржу.
S>Может быть, тогда до вас дойдёт, как такая возможность связана с языком.
Да не связана.
Такая возможность связана с представлением исполняемого кода, а это представление перпендикулярно языку.
Разве ты не видел интерпретаторов Си или Паскаля?
Похоже, у тебя каша в голове из св-в языков и конкретных их компиляторов/интерпретаторов.
Посмотри на Схему — вот тебе оптимизирующий компилятор Лиспа.
Были убраны возможности рантайм рефлексии кода.
Язык, по-сути, тот же.
Отличается представлением скомпиллированного кода, а значит, особенностями модели вычисления.
V>>Сходство с Лиспом там в общей схеме работы интерпретатора, который двухфазный: V>>1. компиляция во внутренее представление; V>>2. исполнение этого внутреннего представления. S>С этой точки зрения более-менее похожи все языки, включая basic.
Все реализации языков, работающие на основе дополнительной исполняющей машинки.
Но не сами языки.
Не осенило еще? ))
Разве ты не видел компиллирующих Бейсиков?
Например, MS Visual Basic for DOS компиллировал в неплохо оптимизированный код (я курочил дизассемблером что он там порождает — да там офигенно, на уровне их же компилятора Си и Паскаля).
V>>Еще отличие Форта в том, что в коде хранится адрес исполняемой процедуры слова, в то время как в Лиспе хранился адрес метаинформации символа, т.е. Чарльз Мур убрал лишний уровень косвенности в процессе работы программы. Однако же, обратным поиском адреса в Форте запросто памятся на "слова". Т.е. Мур сделал размен эффективности оперирования метаинформацией на эффективность исполнения. S>Короче, общего примерно столько же, сколько у вороны с роялем.
Общей была идея двухфазного интерпретатора и представления кода как данных.
Большинство реализаций Форта позволяют сделать декомпиляцию программы. Полученный текст мало отличается от исходного.
И это были первые в мире интерпретаторы, если что.
Просто Мур допилил идею Лиспа до более эффективной, открыв тем самым эпоху достаточно эффективных (в сравнении с Лиспом) интерпретаторов.
Стековая машинка и фаза компиляции интерпретатором в шитый код стали стандартом для реализации интерпретаторов де-факто.
И источником тут является Форт.
Лисп является источником лишь транзитивно, т.к. необходимость борьбы с недостатками Лиспа и породила Форт.
Даже VM джавы и дотнета используют стековую машинку как абстрактную, хотя не используют шитый код...
Но это уже следствие выросших вычислительных мощностей, где у JIT появились ресурсы на генерацию нейтивного кода на лету.
V>>Да и, до первых виденных ЭВМ прилично упражнялся на программируемом калькуляторе MK-61, это тот же Форт, вид сборку. V>>Поэтому, программирование на Форте чуть позже зашло как к себе домой. )) S>Простите, но рассуждения про Форт не очень интересны в контексте ООП.
А зря. ))
ООП в Форте реализуется так же как в Лиспе — через макросистему.
Форт не поддерживает никакую парадигму программирования и поддерживает их все одновременно. Написать набор слов для организации ООП в программе на Форте (а их может быть одновременно несколько и они будут отлично уживаться вместе) гораздо проще, чем решить, какие возможности от этого набора слов требуются.
Напомню, что CLOS — это не более чем попытка стандартизировать библиотечные ООП-возможности.
В Лисп точно так же может сосуществовать сколько угодно много независимых ООП-подсистем библиотечного уровня.
Но! Могут возникнуть вопросы конфликтов идентификаторов макросов и ф-ий таких подсистем.
Именно поэтому потребовалась стандартизация ООП-подсистем в Лисп.
В Форте конфликты имён решаются более чем элегантно через словари, поэтому вопрос стандартизации ООП-расширений никогда не стоял.
Бери любое на вкус.
Исходники любого из этих расширений смехотворны по объёму, т.е. могут быть включены в целевую систему без переживаний по поводу "утяжеления" готового образа — ведь львиная доля этих расширений нужны лишь для первой стадии интерпретации (макросы), а при сохрании оптимального образа ненужный код может быть выкинут.
И насчёт "самолюбования" — я просто вижу любопытствующего чела, который, однако, не обладает необходимой инфрмацией, чтобы понять — почему оно происходило именно так.
Ты не понимаешь мотива принятия некоторых важных решений в IT в ретроспективе.
Проводимый ликбез тебя коробит, но это особенности твоего чванства и ничего более.
В интересные места ведь тебя отсылаю. ))
Было бы любопытно...
V>>Оперирование динамической памятью явное. V>>Это самые базовые слова: V>>- "," — выделить ячейку в динамической памяти и скопировать туда значение с вершины стека; V>>- "@" — читать из памяти число адресу на вершине стека; V>>- "!" — писать число из второй ячейки стека по адресу на вершине стека. S>Это, мягко говоря, совсем не то, что применяется в Лиспе или Смоллтоке.
Ты спрашивал про динамическую память — тебе ответили.
Ключевое тут то, что с помощью базовых примитивов можно расписать сколь угодно сложную систему управления динамической памятью, если по каким-то причинам не устраивает данная изкаробки. В том числе запросто пишется консервативный GC с любой из политик работы, например, какие были приняты в различных реализациях Лиспа — автоматический вызов при исчерпании пула ячеек vs явные вызовы GC.
V>>В Форте можно описать произвольные структуры данных в памяти. S>В ассемблере тоже. Это не делает ассемблер лиспоподобным языком.
Разумеется, речь идёт о выразительности такого описания.
Выразительность Форта при описании объектов выше выразительности Лиспа.
Это из-за особенностей макросистемы Форта — макросы полностью перехватывают выход первой фазы интерпретатора, т.е. в Форт изкаробки включены ср-ва оперирования кишками своей машинки, плюс доступны все слова, из которых состоит "компилятор" первой фазы. Поэтому ООП-расширения Форта смешны по объёму, т.к. вся инфраструктура по парсингу уже есть.
Это и сила, и слабость одновременно, ес-но, как и оно есть у любого достаточно "широкого" инструментария, т.к. больше простора для ошибок.
V>>Сборка мусора в Лиспе, опять же, реализована по-разному. S>Это подробности. Она является неотъемлемой частью языка.
Дудки! ))
Если GC в некоторой реализации требует явного вызова и никогда не вызывается автоматически — это уже подробности не только языка, но принятых решений в этой конкретной реализации.
А каждое настолько важное принимаемое инженерами решение происходит не просто так, разумеется...
Просто ты склонен упрощать из-за недостатка информации по темам, в которых пытаешься расуждать.
Ты мог бы самостоятельно покормить свою эрудицию перед заходом на новый раунд, мне было интересней.
А так уподобляешься шимже, который цинично провоцирует коллег на дележку информацией на блюдечке, разменивая свою лень на своё лицо. ))
V>>В некоторых реализация сборка мусора вызывается каждый раз при исчерпании текущих свободных ячеек в предвыделенном пуле их, что может провоцировать (и провоцировала) сборку мусора даже когда потребности в этом не было, т.е. не было "забытых" объектов. V>>В других реализациях сборка мусора вызывается явно в рамках борьбы такими с холостыми срабатываниями. S>Чегось?
ЧТД. ))
А ведь это были важные отличия реализаций Лиспа.
V>>В любом случае, с многопоточной сборкой мусора в современных VM этот подход имел мало общего. S>Это вообще иррелевантно к данному обсуждению. Речь о языке, а не о реализации.
Бгг...
Если GC не вызывается автоматом, то твои рассуждения "о языке" идут сразу в dev/nul.
V>>Да и сборщик мусора консервативный, а не точный, как в Java или .Net. V>>Т.е. не перемещает данные (не уплотняет память). S>Чегось? Продолжается безудержный бред, да?
Очередное ЧТД.
Исходный и десятки лет реализованный GC не уплотнял память на уровне ячеек.
Он уплотнял только страницы, если/когда эти страницы освобождались полностью.
Но оно же происходит и в обычном менеджере памяти в том же Си безо всякого GC.
Исходный GC связывал освобождаемые ячейки CONS в глобальный список свободных ячеек и не умел ничего более.
Перемещающи/копирующий GC должен уметь корректировать ссылки, а GC Лиспа той эпохи этого не делал.
(Не берусь утверждать за некие потенциальные новые реализации, бо за современным Лиспом не слежу, но десятилетиями оно работало именно так)
Да и, сам вопрос уплотнения памяти в Лисп может стоять только из соображений локальности, т.е. из-за наличия кеш-памяти в современных процессорах.
В эпоху засилья Лиспа было фиолетово для эффективности работы, располагаются ли ячейки подряд или в разных участках памяти.
V>>Т.е., не помогла особо метаинформация. S>Прекрасно помогла.
Не-а.
V>>Второй вариант без проблем может быть реализован в Форте на библиотечном уровне. V>>В Лиспе на библиотечном уровне никак, т.к. отсутствуют встроенные примитивы прямой работы с памятью и соотв. доступ ко внутренним кишкам интерпретатора. V>>(в кое-каких реализациях присутствуют, но это уже намного более поздние эксперименты в попытках привнести в Лисп свойства полее поздних ЯВУ общего назначения) S>В лиспе сборка мусора является частью языка. Отсутствие примитивов прямой работы с памятью — это скорее плюс, чем минус.
Про плюсы/минусы можно рассуждать только в контексте конкретной решаемой задачи.
Если бы у Лиспа были одни плюсы, не нужны были бы другие языки.
V>>С выходом объектного Паскаля и первых версий VB от MS, скорее. S>Это в (бывшем) СССР. А в мире объектные версии Паскаля прошли практически незамеченными массовой публикой.
VB зато широко использовался.
Visual FoxPro тоже, кстате.
S>Попробуйте найти литературу по ООП с примерами на Паскале или VB.
По VB и VFoxPro литературы мильон.
V>>Java изначально ограничила саму ООП-парадигму и .Net совершила ту же ошибку в первоначальном дизайне. S>Мне даже интересно, какие именно аспекты ООП-парадигмы проигнорировала Java.
Я говорю не про игнор, а про наложенные ограничения на реализацию парадигмы.
Джава наложила то ограничение, что экземпляры пользовательских типов будут всегда располагаться в динамической куче, а такого ограничения в исходной парадигме нет.
Это подробности конкретной реализации в неких принятых ограничениях.
V>>Помнишь обсуждение хотя бы новых управляемых указателей на методы в .Net? V>>А обсуждение типов-делегатов все нулевые года? V>>Надо ж было умудриться описать делегаты как объекты, что делегаты с одинаковой сигнатурой стали несовместимы. )) S> Это, собственно, и есть попытки выйти за пределы ООП-парадигмы.
Сотый раз повторюсь — этого не требовалось.
Приличный "почти современный" ООП был реализован еще до Смолтолка, в Алгол-68, и там был функциональный тип и лямбды, т.е. лямбда-исчисление.
Я уже подкидывал тебе мысль, что ФП-подход — это подход системы ограничений к процедурному программированию (функциональный тип был известен еще в эпоху процедурного программирования), в то время как ООП-подход — это инструментарий расширения.
ООП-подход включил известные на тот момент парадигмы целиком.
Дальнейшее развитие ООП-парадигмы и соотв. языков шло в области описания таких ограничений, коль они требуются, ср-вами языка.
Именно поэтому современные ООП-языки принято считать "мультипарадигменными", хотя это не так, разумеется.
S>В чистом ООП никаких делегатов нет. Есть интерфейсы с определёнными сигнатурами.
Мда... Будем разгребать:
Берём абстрактный функциональный ФП-тип.
Этот тип задан своей сигнатурой.
Для целей реализации лямбда-исчисления функциональный тип представлен кортежом { функция, данные }, где абстрактный тип лямбды определён сигнатурой функции.
Где данные передаются через неявно подаваемый this.
В ООП само понятие interface описано как кортеж таких функций.
Это прямо изначально по Барбаре Лисков, если что (главный теоретик ООП, а не этот ботун Алан Кей).
При сокращении кортежа до одной ф-ии получаем абстрактный функциональный тип.
Собсно, делегаты так и реализованы, т.е. никакого выхода за ООП-парадигму в них нет.
"Выход" за ООП-парадигму там можно усмотреть только в выразительности описания таких объектов, бо требуется описать всего лишь сигнатуру единственной ф-ии, и это будет сигнатура метода Invoke.
А разгрести эту кашу можно лишь помня, что в ФП действует "утиная типизация", то бишь, такие функциональные объекты с одинаковой сигнатурой считаются одинаковым типом.
И оно не просто так, а потому что бинарная механика реализаций таких объектов идентична, т.е. бинарной ошибки реинтерпретации памяти быть не может.
В дотнете, однако, делегаты с одинаковой сигнатурой неприводимы друг к другу, хотя обладают такой же бинарной совместимостью.
В этом месте ФП в дотнете заканчивается, толком не начавшись.
S>А несовместимость делегатов с одинаковой сигнатурой в рамках ООП не является самостоятельной особенностью. Она скорее связана с выбором между утиной типизацией и номинативной типизацией.
Ага, т.е. ты хорошо понимаешь про утиную типизацию, просто Ваньку тут валяешь.
Номинативная типизация — это тоже левое ограничение, не требуемое для реализации концепции ООП.
Это просто такое решение, ограничиться именно ею.
Хотя, базовая машинка способна вызывать методы не того объекта через свою систему команд, а вся "загвоздка" была бы только в верификации сгенерированного компилятором кода, верно?
Т.е. всего-то надо было снабдить верификатор возможностью утиной типизации неких типов, помеченных атрибутом как "делегат" (их даже не обязательно было наследовать от базового Delegate, достаточно было наследовать прямо от Object, а остальные ср-ва можно было бы получать от метакласса).
Плюсом было бы то, что загрузчик-верификатор мог бы эффективно "склеивать" попадающие под утиную типизацию такие функциональные типы, т.е. не засорять память копиями одного и того же бинарного кода!
Типов-делегатов ведь овердохрена, но уникальных сигнатур потенциально меньше.
Все эти Action<> и Func<>, таки, выглядят крайне ущербно — как попытка залатать исходно присутствующую дыру во фреймворке.
V>>Это серьёзный косяк, как ни крути. V>>C++ эту ошибку не совершал. S>Скажем, в С++ два одноимённых типа с "одинаковой сигнатурой" ничуть не более совместимы между собой, чем в дотнете.
1. На шаблонном уровне совместимы.
2. Компилятор склеивает идентичный бинарный код различных типов.
А в дотнете ни ограничения в генериках на абстрактную сигатуру делегата не задать, ни описать эту абстрактную сигнатуру явно, скажем, где-то так:
Об костыли Action<> и Func<> мы спотыкаемся сразу же, когда речь идёт о модификаторах, например ref/in/out, а недавно еще появились scope и readonly.
Плюс аргументами генериков не могут быть ref-структуры, поэтому, приходится описывать типы делегатов ручками как в старые добрые времена, когда генериков еще не было, бгг...
S>Это в ФП подобные проблемы возникнуть не могут, т.к. там совместимость любых функций с одинаковой сигнатурой ставится во главу угла.
Разумеется, но это же без проблем.
Просто считается, что любой функциональный тип с одной сигнатурой — он ровно один на всех.
Тут проблем нет.
И не зря в функциональных типах часто развита система алиасинга типов (аналог typedef в Си/С++).
Слава богу, в 2022-м появился global using в C#. ))
Пара десятилетий потребовалось для вменяемого алиасинга.
Но это должно было быть сразу, и под функицональынй тип должна была быть механика неявного алиасинга, как в ФП.
В общем, придирки к дотнету в этом вопросе не в том, что они чего не придумали сами (за это их никто бы не полоскал), а за то, что не взяли уже давно придуманное и отлаженное.
Причём, это не какая-то мелочь, а самая базовая весч, которую они же взялись реализовать сразу же — функциональынй тип!
Ну так и делайте его ровно так, как он уже давно отшлифован как в концепции, так и в реализации этой концепции что на уровне компилятора, что в бинарном виде.
Там же, хосподя, примитивщина всё.
Например, по выходу дотнета за несколько вечеров я накатал компилятор ограниченной реализации Схемы.
Ты бы знал, как я матерился, выбирая представление функционального типа в конечном образе, ууу...
Зато освоил способы описания типов-делегатов "на лету", в процессе работы компилятора.
Разумеется, у меня был глобальный словарь всех уникальных сигнатур, встреченных программой.
Т.е., в наколенном варианте за несколько вечеров это решить можно, а на уровне инфраструктуры "забыли", угу...
При том, что F# был одним из первых реализованных языков.
Я не зря потом купил книгу одного из авторов дотнета, как они описывали процесс создания фреймворка, мне просто было интересно, как ои до такого дошли.
Книга написано вполне читабельно, но вызывает сожаление — они "тренировались на кошках" в основном в деле реализации C# и Питона.
При том, что Питон под дотнет так и остался невостребован.
Лучше бы разрабатывали его из F# и C#.
S>А в лиспе так и вообще, одинаковость сигнатуры не является критерием.
Ес-но, тут динамическая типизация vs статическая.
Но утиная типизация или нет перпендикулярна статической типизации, прикинь? ))
Порвал шаблончик или нет?
(опять и снова отсылаю к статически компиллируемым ФП-языкам)
V>>Повторяю в сотый раз — "чисто ФП-шные" штуки были в ООП чуть не в первых ООП-языках. V>>Например, в том же Алголе-68. V>>Т.е. функциональный тип как первоклассный в языке, лямбды. S>Мне кажется, вы слишком смело называете Алгол ООП-языком. Никакого ООП в нём не было.
Я называю Алгол-68.
Это первый полноценный ООП-язык.
V>>Симула, кстате, была тоже лишь попыткой объектного расширения Алгола. S>Как так — взяли ООП-шный алгол и попробовали привинтить к нему "объектное расширения"?
Ну да.
Берется язык со всем его синтаксисом и стандартной библиотекой.
Берутся исходники всего этого.
Допиливается.
Получается Симула, которая практически тот же Алгол.
Но работы была проведена недостаточно качественно в 67-м, поэтому появился Алгол-68.
На Симуле обкатали концепции, но недоделки стали видны сразу же — этот язык не мог претендовать на роль языка общего назначения.
Поэтому Алгол 68 уже мог.
Симулу могли бы назвать "Объектным Алголом".
Похоже, тебя чуть сбивает с толку совсем левое название языка. ))
Тот же Алгол, хосподя...
Мы тут говорили о коде как о данных.
Это появилось только с метаклассами в Смолтолке-80.
До этого никакой рефлексии не было.
Что касается ООП-парадигмы — она была уже давно обкатана до первых версий Смолтолка.
Смолтолк — это попытка выделить ООП-парадигму "в чистом виде".
Никакой практической пользы "чистота ООП" Смолтолка не имела до введения метаклассов аж в 80-м году, когда стало возможным проводить инспекцию кода, рефакторить и всё это было обёрнуто в IDE.
Поэтому, заслуга Смолтолка не в ООП-парадигме, а в развитой системе метаинформации об ООП-like объектах.
В возможности динамического создания типов и экземпляров этих типов.
А ты тут в очередной раз показываешь непонимание, откуда у чего растут ноги в IT. ))
Причина-следствие, причина-следствие... Это же важно, не?
V>>Для этого значение должно быть const в контексте внешнего кода. S>Не-не-не, Дэвид Блейн. Вот я пишу свой код. И в нём мне бы хотелось полагаться на то, что его вызывают не с чем попало, а с неизменяемым объектом.
Да какие проблемы (мать, мать, мать...) — опиши сам объект как неизменяемый.
Тебе показать, как описывать иммутабельные объекты в С++?
Модификатор const к ссылке/указателю на объект разрешает вызывать только const-методы этого объекта.
То бишь, предполагается, что у этого объекта могут быть и не const-методы.
Я что в тот раз фигел от твоего непонимания сей элементарщины, что сейчас...
Заметь, в дотнете для структур ввели аналогичную семантику readonly для методов.
Поэтому, если структура передаётся по readonly ref-ссылке (кратно in), то можно вызывать только readonly методы.
В точности как в С++.
Неужели все вокруг идиоты и не понимают, ЗАЧЕМ это делается именно так? ))
Похоже, не понимаешь только ты, считая всех вокруг заранее идиотами.
V>>Т.е. значение может быть const по всей иерархии "внешности", вплоть до объявления. S>Внешний код ещё не написан — каким образом я смогу потребовать от него const на этом значении "по всей иерархии внешности"?
Но тип аргумента-объекта уже должен уже быть? ))
V>>Это на выбор программиста. S>
Ну да.
Хочешь полной иммутабельности — не запрещено.
Хочешь частичной — тоже велкам.
Выбирай наиболее эффективную стратегию решения конкретной задачи.
V>>Что будет лишь малой частью всех возможных сценариев по слишком очевидной причине (тут уже сложно не материться) — ввиду наиболее сильного наложенного на сценарий ограничения. S>Ок, как видим, вы так и не поняли, что такое иммутабельность, и почему она ортогональна const.
Мы видим несколько иное — чванливость Синклера, который иногда не в состоянии воспринимать информацию по причине ЧСВ и более ни по какой. ))
V>>Странно, что мы вообще спорили тогда и сейчас вокруг подобной элементарщины... S>Да ничего странного — у вас отсутствует обучаемость. Годы идут, а вы так и не вышли за пределы своих заблуждений.
И даже сейчас ты не понял, как описывать иммутабельные типы в С++?
Признайся, уже понял и тебе дико стыдно.
S>В качестве упражнения можете попробовать спроектировать на С++ пару абстрактных классов — изменяемый вектор и immutable вектор. В терминах дотнета это были бы IImmutableList<T> и IList<T>. И посмотрите, можно ли их отнаследовать друг от друга; можно ли получить один из другого при помощи модификатора const; понадобится ли вообще модификатор const при проектировании этих классов или при их использовании.
1. В дотнете я могу породить мутабельный тип из IImmutableList<T> аж бегом и со свистом.
2. В этой же технике в точности аналогично можно и в С++.
Ты не там гарантии иммутабельности ищещь.
Гарантии иммутабельности может иметь только сам тип.
Еще в прошлые разы я обращал твоё внимание на то, что более выгодно с практической точки зрения, чтобы не твой код требовал иммутабельности объекта, а чтобы внешний код требовал, чтобы твой код не мог модифицировать объект.
Почему так? — по очевидной причине, ведь твой код тогда сможет работать как с тру-иммутабельными объектами, так и с неиммутабльными при рождении, но которые решили сделать иммутабельными "чуть позже". Например, некий достаточно сложно инициализируемый ветвистый словарь чего-то там.
В целях эффективности в момент наполнения словарь может быть мутабельным, а потом в какой-то момент владение передаётся константной ссылке/указателю и ву а ля.
В отсутствии const в этом сценарии потребуется два типа — мутальный и иммутабельный, где готовый мутабельный словарь копируется в иммутабельный, с соответствующими накладными расходами и прессингом на память. В С+ в этом сценарии достаточно скопировать ссылку/указатель.
Мне казалось, что ты понял эту особеность уже тогда, коль закончил пререкаться...
Но сейчас, смотрю, тебя всё еще распирает от врождённого упрямства "это ВЫ чего-то не понимаете, а не Я!!!111"
Значит, ни хрена ты не понял.
Походу, и не пытался, наивно надеясь, что всё понимаешь и так.
Не всё.
Здравствуйте, Baiker, Вы писали:
B>Smalltalk же! Написали язык в соотв. с теорией. Бери и пиши. Но т.к. эти концепции обосрались при проверке временем, крайне непонятно, зачем СЕЙЧАС подымать эту пыль. Мальчик познаёт мир?? Ну давайте теперь во всё тыкать, что ты прочёл — лисп, смоллток, рефал, оберон, пролог, оккмл... не надоело труху перебирать?
Концепции, реализованные в смоллтолке вовсе не "обосрались". Просто язык опередил свое время.
Где-то читал, что смоллтолк не получил распространения, потому что, во-первых, он был достаточно медленным (по сравнению со статически типизированными языками), а во-вторых, среды разработки для него были платными и очень дорогими (смоллтолк это полноценная среда разработки, а не просто интерпретатор).
В смоллтолке присутствовали элементы функционально программирования (функции высшего порядка), были отличные библиотеки работы с коллекциям (ага, как в C# сейчас, только еще лучше), любое поведение любого объекта можно было посмотреть, изменить. В языке был супер синтаксис — гибкий как лисп, но без огромного количества скобочек. Писать на нем легко, а отлаживаться — очень легко, потому что среда разработки это то же, что и среда исполнения.
А некоторые концепции так и не были повторены в других языках. Например, возможность изменять и сохранять состояние системы. Т.е. работающую программу можно остановить, сохранить, и позже восстановить и запустить. Или возможность изменять все элементы системы — "системные библиотеки" и т.п.