Metaobject Protocol для базового Perl 5 |
||
МЕНЮ Главная страница Поиск Регистрация на сайте Помощь проекту Архив новостей ТЕМЫ Новости ИИ Голосовой помощник Разработка ИИГородские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Искусственный интеллект Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Психология ИИ Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Творчество ИИ Техническое зрение Чат-боты Авторизация |
2022-05-17 14:47 Идея создания Metaobject Protocol (MOP) для Perl 5 витала достаточно давно. Хорошо известна одна из реализаций — Class::MOP, которая используется в Moose. Но попасть в базовую поставку Perl 5 может лишь такое решение, которое будет совместимо с существующей объектной моделью и не будет перегружено излишними возможностями и зависимостями. На днях Stevan Little опубликовал первый пробный релиз на CPAN возможного кандидата на это вакантное место — модуль mop. Проект прошёл долгую эволюцию, за процессом внимательно следило сообщество. Давайте же рассмотрим, что получилось и какие последствия это может иметь для Perl 5. Что такое MOP? Metaobject Protocol (метаобъектный протокол) — это программный интерфейс для управления системой объектов в языке. Так же, как объект является экземпляром класса, сам класс представляется объектом (или метаобъектом) с программно задаваемыми свойствами (атрибутами, методами и т.д.). Как выразился Stevan Little, объясняя своей маме что делает Moose: Это абстракция для системы абстракций, используемая для создания абстракций Имея дело с классами в базовом Perl все мы сталкивалось с простейшей реализацией MOP:
Эта крипто-запись в процессе работы программы добавляет метод bar для класса, указанного в переменной $foo , который является ссылкой (алиасом) на функцию baz . Если кому-то знаком термин reflections, то это также является одним из его примеров. Отличие же MOP от reflections в том, что он предоставляет удобный и гибкий инструмент для разработчика для метапрограммирования классов без необходимости использования полулегальных хакерских техник. Например так:
Зачем нужен MOP в базовой поставке Perl? Если обратиться к классической книге о MOP — «The Art of the Metaobject Protocol», которая описывала реализацию метапротокола в CLOS, одной из основных предпосылок создания протокола являлась необходимость решить проблему с многообразием реализаций объектной системы для языка Lisp, которые были несовместимы друг с другом. Метапротокол позволял строить совместимую, гибкую и расширяемую объектную систему, которая удовлетворила бы все запросы Lisp-программистов. Эволюция mop Разработке модуля mop предшествовал очень долгий путь. Stevan Little после участия в работе над объектной системой для Perl 6 в компиляторе Pugs, решил перенести полученные наработки в Perl 5. После нескольких попыток появился модуль Class::MOP, который стал основой для создания Moose. Moose стал очень популярен, поскольку дал разработчикам тот инструмент для работы с классами, который они так долго ожидали. Но долгое время старта программ на Moose и большое дерево зависимостей отпугивало потенциальных пользователей. Поэтому два года назад Стивен загорелся идей создания компактной системы MOP, которая могла бы войти в базовую поставку Perl. Так возник проект p5-mop, но он оказался раздавлен весом своей собственной сложности, что несколько разочаровало Стивена и привело его к неожиданному эксперименту — проекту Moe, реализации компилятора Perl 5 на языке Scala. Работа с mop Установка Для установки mop можно воспользоваться cpanm:
Обратите внимание, что mop активно использует новые возможности Perl, такие как Perl parser API. Минимальная версия Perl, необходимая для работы модуля, — 5.16. Первый пример Рассмотрим пример кода с использованием mop:
Класс задаётся ключевым словом class . Сначала декларируется класс Point , в котором определяются атрибуты с помощью ключевого слова has . Обратите внимание, что переменные атрибутов для отличия от обычных переменных задаются с помощью твиджила (twigil или двухсимвольный sigil). Это практически полностью копирует синтаксис Perl 6. На данный момент поддерживаются только атрибуты с твиджилом $! , которые являются приватными атрибутами.После указания твиджила следуют описания свойств (traits) после ключевого слова is . Например, ro означает, что атрибут доступен только на чтение. После знака равно задаётся значение атрибута по умолчанию. В классе Point задаётся единственный метод clear , который сбрасывает значения атрибутов. Видно, что переменные атрибутов $!x , $!y доступны внутри методов как лексические переменные в области видимости данного класса. Их значения замыкаются в пределах каждого экземпляра класса.
Здесь определяется класс Point3D , который становится наследником класса Point с помощью ключевого слова extends . Таким образом, полученный класс перенимает все атрибуты и методы класса Point . В дополнении к ним в классе задаётся атрибут $!z . Также переопределяется метод clear , который, как видно из листинга, производит вызов следующего (в иерархии наследования) родительского метода clear из класса Point с помощью next::method . Кроме того, автоматически внутри каждого метода определяется переменная $self , являющейся ссылкой на текущий объект.В случае если не указаны классы для наследования, класс по умолчанию наследуется от класса mop::object . Это продемонстрировано в следующем примере:
Атрибуты объекта могут быть заданы при создании экземпляра класса:
Обратите внимание, что мы не задавали метода new для класса Point . Это метод унаследован из класса mop::object .Для доступа к значению атрибута автоматически создаётся метод-геттер, например:
Будет выведено значение 1 . Поскольку атрибут объявлен как ro , то попытка его изменить приведёт к runtime-ошибке:
Тем не менее внутри методов мы можем свободно изменять любые атрибуты, например, можно создать метод-сеттер set_x :
В данном примере также наглядно видно как можно задать сигнатуру метода, т.е. описать переменные аргументов, передаваемых в метод, и даже задать значения по-умолчанию, если аргумент опущен.
В то же время атрибуты находятся в области видимости только для класса Point, т.е. мы не можем напрямую оперировать с ними в классе наследнике
Это выдаст ошибку компиляции: No such twigil variable $!x Роли Роли позволяют гибко компоновать классы необходимыми методами и атрибутами, позволяя избегать множественного наследования.
Данная роль определяет два метода win и loose . Метод win не имеет тела, значит в этом случае метод должен быть обязательно определён в составе класса, который исполняет данную роль. В этом отношении роль похожа на понятие интерфейса, присутствующего в других языках программирования.Теперь класс можно скомпоновать с данной ролью с помощью ключевого слова with :
Класс может компоноваться из нескольких ролей, в этом случае названия ролей перечисляется через запятую. Свойства и значения атрибутов
Свойства атрибутов записываются через запятую, после ключевого слова is. На данный момент поддерживаются следующие свойства:
При задании значения по умолчанию следует помнить, что на самом деле после знака равно идёт исполняемая конструкция, т.е. запись:
Означает
Т.е. по сути — это функция для создания значения, а не присвоения заданного выражения. При задании значения по умолчанию можно ссылаться на текущий экземпляр объекта с помощью переменной $_:
Если требуется, чтобы при создании объекта с помощью new был обязательно задан определённый атрибут, в значении по умолчанию для него можно указать такой код:
Соответственно, если значение атрибута foo не будет задано при создании объекта, то произойдёт исключение.Проверки типов, классов у атрибутов и методов не реализованы, чтобы не перегружать ядро mop излишней сложностью. Однако такие проверки легко могут быть выполнены в виде внешней функции:
Рабочую реализацию функции type можно увидеть в примере для модуля mop. Создание модуля Типичный файл модуля может выглядеть так:
Как видно из примера, если указан package , то имена классов получают соответствующий префикс. Кроме того, класс получают доступ к области видимости модуля. Это значит, что функции и переменные, определённые в области видимости модуля, также доступны для использования внутри классов. При этом такие функции не становятся методами класса. Больше никакого загрязнения пространства имён экспортированными функциями!Специальный метод BUILD может использоваться в том случае, если при создании объекта требуется какая-либо инициализация. Это удобно и позволяет не переопределять метод new .Метод DEMOLISH вызывается при уничтожении объекта, т.е. представляет собой деструктор.Внутреннее строение объекта в mop Объект создаваемый mop не является привычной многим blessed ссылкой на хэш. Вместо этого используются так называемые InsideOut объекты, где вся внутренняя структура скрыта в коде класса и доступна только через специальные методы. Существует несколько публичных методов в mop, которые позволяют проинспектировать внутреннюю структуру объекта:
Практическое использование Модуль mop на данный момент проходит активное тестирование сообществом. Основная рекомендация — возьмите любой модуль и попробуйте переписать его с использованием mop. С какими ошибками и проблемами вам придётся столкнуться? Напишите об этом, это здорово поможет в дальнейшем развитии проекта. Например, был успешно портирован модуль Plack, все 1152 теста которого успешно пройдены. Сейчас трудно сказать будет ли принят mop в состав базового дистрибутива Perl. Если будет принят, то начиная с какой версии: 5.20, 5.22 или более поздней? Это неизвестно, но общий весьма положительный фон вокруг события воодушевляет. Источники
Источник: habr.com Комментарии: |
|