Meta-Object Protocol в Perl6

от автора

В некоторых языках программирования существует интерфейс для создания класса не через его определение, а через выполнение некоего кода. Этот API называется Meta-Object Protocol или MOP.

В Perl 6 есть MOP, позволяющий создавать классы, роли и грамматики, добавлять методы и атрибуты и делать интроспекцию классов. К примеру, вот как в Rakudo можно использовать вызовы MOP, чтобы узнать, как реализован тип Rat (рациональные числа). Вызовы методов MOP обычно начинаются не с точки, а с .^

 $ perl6  > say join ', ', Rat.^attributes  $!numerator, $!denominator  > # список всех методов слишком длинный,  > # поэтому мы сделаем случайную их выборку  > say join ', ', Rat.^methods(:local).pick(5)  unpolar, ceiling, reals, Str, round  > say Rat.^methods(:local).grep('log').[0].signature.perl  :(Numeric $x: Numeric $base = { ... };; *%_) 

Большинство строк должны быть понятны: у объектов класса Rat есть два атрибута, $!numerator и $!denominator, и много методов. Метод log принимает значение Numeric как вызывающий метод (это отмечено двоеточием после имени параметра) и необязательный второй параметр $base, у которого есть значение по умолчанию (число Эйлера e).

Хороший пример использования можно взять из интерфейса баз данных Perl 6. У него есть возможность записывать вызовы объекта в log, ограничив при этом запись методов одной конкретной ролью (к примеру, только роли, которая занимается вопросами соединения с базой, или же вопросами извлечения данных). Вот пример:

 sub log-calls($obj, Role $r) {      my $wrapper = RoleHOW.new;      for $r.^methods -> $m {          $wrapper.^add_method($m.name, method (|$c) {              # вывести протокол выполнения              # note() пишет в standard error              note ">> $m";              # вызвать следующий метод с тем же именем и              # теми же аргументами              nextsame;          });      }      $wrapper.^compose();      # оператор 'does' работает так же, как 'but', но      # изменяет только копию объекта      $obj does $wrapper;  }   role Greet {      method greet($x) {          say "hello, $x";      }  }   class SomeGreeter does Greet {      method LOLGREET($x) {          say "OH HAI "~ uc $x;      }  }   my $o = log-calls(SomeGreeter.new, Greet);  # записали в log, поскольку это отработала роль Greet  $o.greet('you');  # не записали в log, поскольку это не та роль  $o.LOLGREET('u'); 

Выводит:

 >> greet  hello, you  OH HAI U 

С использованием Meta-Object Protocol классы, роли и грамматики становятся доступны вам не только через специальный синтаксис, но и через обычный API. Это добавляет гибкости в ООП-код и позволяет проводить интроспекцию и изменения объектов.

ссылка на оригинал статьи http://habrahabr.ru/post/265199/


Комментарии

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

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