В текущей нестабильной ветке alterator произошло большое изменение: там внедрены объекты. Зачем это нужно? Нужно это для того, чтобы поддерживать код alterator было легче, чтобы убрать старые хаки, уменьшить количество cond и case, затрудняющих чтение. Что это такое? Читайте далее...
Эта цитата принадлежит Norman Adams и сейчас вы убедитесь насколько это верно ;)
Любая созданная процедура запоминает своё окружение вместе со всеми определёнными там переменными и другими функциями. При этом запоминает настолько хорошо, что куда бы далее вы ни передавали эту процедуру, она будет работать именно с тем окружением, в котором родилась (подобно тому как цыплята, кого увидят первым, вылупившись из яйца, того и считают мамой), данные окружения будут существовать до тех пор, пока они требуются хотя бы одной процедуре. Например:
Здесь функция +three, появившись, запомнила, что x – это 3, и при всех последующих запусках будет работать именно с этим значением, даже если мы явно зададим x значение 10.
Итак, у нас есть «память», а если есть «память», значит можно сделать функции с состоянием, иначе говоря объекты.
Вот например простейший объект, изображающий точку на плоскости:
Вот теперь ясно видно, что имея замечательное свойство «памяти», можно создавать то, что в других языках программирования называют объектами, то есть совокупность данных и методов, работающих с этими данными. То, как именно строить объекты – никто вас не ограничивает, поэтому существует множество вариантов объектных систем для Scheme. Система объектов Alterator похожа на объектную систему T.
Работают с объектами, как правило, одним из двумя способами: явно обращаясь в методам или данным или передавая объекту сообщение. Эти способы совершенно равноценны. Просто в одном языке удобнее вызвать метод:
В другом, послать объекту сообщение с желанием выполнить метод:
Как вы догадываетесь, в LISP принято использовать второй способ.
На вводимые дальше объекты можно смотреть как на существенно улучшенные функции.
С одной стороны объект будет содержать в себе собственно тело функции, с другой стороны у него будет «вторая дверь», через которую можно будет вызывать определённые в объекте операции. То есть мы получаем объект «функция с рычагами».
Общий формат процедуры создания объектов следующий:
<proc> – выражение которое будет исполняться при каждом вызове объекта (дверь #1). <methods> – набор определённых операций (дверь #2). Операций может и не быть.
Вырожденный случай (есть только дверь #1):
Это тоже самое что и просто процедура:
Методы описываются в следующем формате:
Здесь:
Как же войти во вторую дверь? Для этого существуют так называемые операции.
Создаётся операция при помощи инструкции (operation имя)
Можно сразу создать и определить операцию (define-operation имя). Последняя конструкция полностью аналогична операции (define имя (operation имя))
Создадим объект точки на плоскости:
У процедуры operation есть ещё один необязательный параметр – действие по умолчанию. В случае если та или иная операция не была обнаружена, то будет запущено действие по-умолчанию. Если действие по умолчанию не определено, а требуемая операция в объекте не обнаружена, то будет выдано сообщение об ошибке и исполнение кода прервётся.
Небольшой пример:
Это неприметное на первый взгляд действие по-умолчанию позволяет творить чудеса. Вот так например можно сделать предикат различающий только интересующие нас объекты
Возможны и другие фокусы ....
Можно усложнять «маршрутизацию сообщений», тем самым создавая то, что в других языках программирования называют «наследованием» и «иерархией объектов».
Для комбинирования объектов используется процедура join. В результате применения join
объектам (object proc1 method11 method12 ...) (object proc2 method21 method22 ...)
Получится объект (object proc1 method11 method12 ... method21 method22 ... ).
Создадим объект точки в пространстве:
Все примеры выше не являются по сути вызываемыми объекты. Где же могут быть полезны настоящие двудверные функции-объекты?
Возьмём пример из самого alterator.
Создадим объект «пустой атрибут». Если у него спросить имя атрибута, то он его вернёт, а любые попытки вызова интерпретируются как пожелание задать данному атрибуту значение и в результате возвращается объект «атрибут со значением». Последний также воспринимает сообщения на предмет получения его имени и значения, а все попытки вызова интерпретирует как пожелание добавить ещё одно значение, то есть в результате возвращается атрибут с расширенным значением.
Пример:
Такое поведение очень удобно использовать в описании интерфейса
Описываются эти необычные объекты очень и очень просто:
Ну вот и всё. Объектная система простая – как и всё в Scheme.
Какие же объекты применяются в самом alterator?
Также применяются объекты для нативных бакендов alterator.
....