Введение
Продолжая писать про io, совершенно необходимо остановиться отдельно на устройстве объектной системы этого чудесатого езычка. Главная проблема в том, что даже если вы «знаете» ООП, вполне может сложиться ситуация, что вы просто не поймете, как оно устроено в io. Сейчас под ООП почему-то подразумевается модель Java, чаще всего. C++ нельзя назвать объектно-ориентированным языком, потому что он язык поддерживающий парадигму ООП, но это не его основная парадигма. Java больше подходит под гордое звание Ъ-ООП языка, но вот беда, ООП диктуемое Java-like языками довольно извращено. Изначально принципы ООП зарождались в Smalltalk'е и там все выглядело несколько иначе, объекты общались друг с другом не посредством вызова методов, а посредством передачи друг другу сообщений, мне до сих пор странно, почему же от этой модели ушли, ведь такое построение позволяет ввести прозрачную параллельность в язык без костылей. Посмотрите на нынешние круто параллелящиеся языки, тот же Erlang например, там все сделано через сообщения. Опять же нагородили огородов из RPC, COM и прочего dbus'а. А ведь как все хорошо начиналось.
Прототипное ООП
Мы как-то привыкли к тому, что ООП строится на классах. Класс — описание типа, объект — экземпляр класса. В целом такая модель очень хорошо себя зарекомендовала в нелегком деле разделения логики и данных, однако внесла дополнительную путаницу в программы. Вам нужно держать в голове все экземпляры класса, а так же сам класс. Вопрос, конечно, спорный и желания наезжать на классическую модель «класс-объект» у меня нет, но рассказать о преимуществах прототипов все-таки хочется.
Глянем на прототипы, в двух словах я описывал структуру в первой статье, но на всяких случай напомню. Прототипность языка заключается в том, что напрочь отсутствуют такие понятия как класс, экземпляр класса и прочее связанное с разделением декларации типа и данных, в io есть только объекты. Объект всегда имеет свой инстанс (как это по русски будет?), получить новый объект можно клонировав старый и изменив его свойства, добавив/убрав из него нужные слоты. Таким образом мы убиваем сразу целый косяк грызунов: у нас есть активный объект, свойства/методы которого доступны для использования и он же является прототипом («декларацией класса») для своих потомков. Очень отдаленно (ну о-о-о-очень отдаленно) такая структура напоминает статические классы.
Объекты которые есть всегда
Сразу после запуска интерпретатора вам доступны несколько «глобальных» объектов, пожалуй самые важные из них вот эти:
- Lobby
- Object
Первый объект хранит в себе рантайм и является, так сказать, почвой под ногами у выполняемого кода. Второй — базовый объект для клонирования, чаще всего первыми строками исходника на io бывают
То есть даже когда вы пишите вроде бы не «объектно», вы все-равно пишете объектно. Например код:
<font color="#9acd32">factorial</font> <font color="#8fbc8f">:=</font> <font color="#8b8378">method</font>(number, <font color="#8b8378">if</font>(<font color="#9acd32">number</font> <font color="#8fbc8f">==</font> 0, 1, number <font color="#8fbc8f">*</font> factorial(number <font color="#8fbc8f">-</font> 1) ) ) factorial(5) <font color="#8b8378">print</font>
Создает вовсе не функцию факториал, он создает слот факториал в объекте Lobby.
Lobby является контекстным объектом, пока явно контекст не переключается на другой объект.
Немножко вуду
Объекты в io интроспективны, то есть вы можете копаться у них в кишках как вашей извращенной натуре только захочется, если у вас есть какой-то непонятный объект, вы всегда можете посмотреть чего у него внутре (
<font color="#00ff00">Lobby</font> <font color="#8b8378">slotNames</font> <font color="#8b8378">print</font>
Это уже началось метапрограммирование, тема отдельной статьи, пока я только упомяну то, что вы можете «на лету» делать с объектами такие штуки, которые ни в одном немецком фильме не показывают.
Модульность
Может это и тема отдельной статьи, но пробежаться надо в любом случае. Конечно io модульный язык, иначе не могло быть просто потому, что не могло быть. Причем модульность в io сделана крайне прикольным образом, тут нет никаких import/include/require_once, тут все проще. Есть некий модуль Z_Importer, который загружается вместе с интерпретатором в память, как только вы пытаетесь использовать какой-либо объект не входящий в лексический обзор текущего файла, этот самый модуль ломится искать файл с именем объекта. Сначала в текущем каталоге, потом по каталогам библиотек (указываемым методом addSearchPath). Допустим классы Mushroom, Lenin и Man из первой статьи лежат в отдельных файлах. Как накормить мужика?
Mushroom <font color="#cd5c5c">//Достали грибочек из Mushroom.io </font>Lenin <font color="#cd5c5c">//Достали Владимирильича из Lenin.io </font>Man <font color="#cd5c5c">//Достали мужыка из Man.io </font> Man eat(Mushroom) Man state println
По-моему это самый дзэнский импортер из всех, которые я видел (:
Ну и все, пожалуй
Вроде бы это все, что нужно знать о объектной модели io, главное помнить про сообщения, но это уже совсем другая история (:
Ссылки
Если кому-то интересно что, где когда и как, можно почитать референс по io: http://iolanguage.com/scm/git/checkout/Io/docs/IoReference.html
А еще мы вчера наколбасили русскоязычный irc-канал про io: #io-ru@FreeNode, ждем заинтересовавшихся (:
P.S. У вас тут, между прочим, в минусах сидит один из знатоков io (А в догонку еще и разработчик StrokeDB) — oleganza, я хочу попросить, что бы он поправил меня или дополнил, если я где-то ошибся или чего-то недоговорил.
(Из моего блога)