IO — добрый брат-близнец JavaScript

Читаю прелюбопытнейшую книжку — «Семь языков за семь недель«. Языков программирования, разумеется. Читаю и пребываю в перманентном восторге. По списку идут Ruby, IO, Prolog, Scala, Closure, Erlang и Haskell, и я только-только добрался до Scala. Prolog, разумеется, здорово прошелся по психике в шипастых сапожищах, но больше всего в душу запал IO.

Оказывается, кроме JavaScript в мире существуют другие прототипные языки программирования, такие как IO, и JavaScript не обязательно хорошо смотрится на их фоне. Меня впечатлили три момента.

Момент 1: создание объектов.

В IO объекты не создаются, а клонируются.

Поскольку это клон, его поле (слот)  proto, разумеется, указывает на Object .

Всё прозрачно и очевидно. Сразу ясно, кто объект-папа, и каким образом он получил потомство.

В моём любимом JavaScript узнать, кто папа, можно только после генетического теста или чтения мануалов.

Те редкие люди, которые подумали, что __proto__  указывает на Object  либо  null , бесконечно неправы, потому что он указывает на Object.prototype .

({}).__proto__ === Object.prototype //true

А Object — это вообще функция. Можно выпендриться и возразить, мол, функции в JavaScript это всего-лишь исполняемые объекты, но это читерство.

Создание объектов через функции-конструкторы — это вообще фантастический изврат.

Если забыть new  перед функцией-конструктором, получим undefined . Если не забыть new , но вернуть из функции что-либо кроме примитивов — созданный объект потеряется в преисподней. Ну и да, прототип создаваемого объекта берется из Point.prototype . Всё можно понять и объяснить, но зачем???

Легион JavaScript программистов на протяжении многих лет пытался эмулировать классовое наследование, потому что синтаксис к этому всячески подталкивает. С синтаксисом IO такое бы даже в голову не пришло.

Момент 2: обмен сообщениями.

Вместо того, чтобы вызвать метод или обратиться к полю напрямую, мы отправляем объекту сообщение, а тот уже смотрит, есть ли такой слот. Если есть, возвращает значение или вызывает метод. Если нет — может и упасть.

Звучит просто, но последствий от такого дизайнерского решения уйма. Во-первых, оно совсем по-другому читается. Во-вторых, входящее сообщение можно всячески исследовать изнутри обработчика — проверить имя, аргументы, перенаправить другому объекту. Например, вот так метод может узнать, под каким именем его прилепили к объекту:

Анархия начинается, если прикрепить к объекту обработчик неизвестных сообщений.

Момент 3: IO бесконечно расширяемый.

В IO можно добавлять свои и убирать существующие операторы, можно расширять синтаксис, можно вообще удалить clone метод у Object, и текущий рантайм будет безвозвратно испорчен.

Просто из чистого вандализма, я бы запретил числам делиться:

Но параллельно добавил бы поддержку массивов-литералов [] , как в JavaScript:

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

Всё, что внутри квадратных скобок, передается в метод squareBrackets, а doMessage исполняет аргументы как сообщения, чтобы положить в массив готовые результаты.

В IO есть свой эквивалент method_missing от Ruby. Называется он forward , и будет вызван, если объект получил незнакомое сообщение:

Одним словом, рай для метапрограммирования.

Резюме.

В продакшен IO я бы однозначно не пустил. Время от времени интерпретатор вывалился с какой-то ошибкой на вполне безобидных примерах. Но я давно не получал такого удовольствия, делая программистские задачки. Много наблюдений, много мыслей, и очень интересно сравнивать IO с JavaScript в вещах, которые уже давно воспринимал как понятную данность. То же создание объектов, отношение к прототипам, и общее восприятие готовых программ. Мозг пострадал, но стал больше.

3 комментария для “IO — добрый брат-близнец JavaScript

  1. Уведомление: - Dots and Brackets

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *