Написание признака атрибута

Я собираюсь выбрать, какой язык использовать для нового проекта: Perl5 или Perl6. Пока 6 побед, за исключением того, что он отсутствует Mooленивые атрибуты. В двух реализациях, которые я обнаружил в модулях, отсутствует ключевая функциональность. Отсюда моя попытка написать собственную реализацию.

Роль против Класса

Первая проблема, с которой я столкнулся - это содержание атрибута. .package за одного заявленного в роли. Рассмотрим следующее:

 role HOW1 {
     method compose ( Mu $class ) {
         note "HOW1.compose";
         nextsame;
     }
 }

 role HOW2 {
     method compose ( Mu $class ) {
         note "HOW2.compose";
         nextsame;
     }
 }

 multi trait_mod:<is> (Attribute:D $attr, :$mooish!) {
     note "Attribute's package.HOW: ", $attr.package.HOW;
     note '$*PACKAGE.HOW: ', $*PACKAGE.HOW;
     $attr.package.HOW does HOW1;
     $*PACKAGE.HOW does HOW2;
 }

 class Foo {
     has $.bar is mooish;
 }

 role FooRole {
     has $.baz is mooish;
 }

Вывод скрипта следующий:

Attribute's package.HOW: Perl6::Metamodel::ClassHOW.new
$*PACKAGE.HOW: Perl6::Metamodel::ClassHOW.new
HOW2.compose
HOW1.compose
Attribute's package.HOW: Perl6::Metamodel::GenericHOW.new
$*PACKAGE.HOW: Perl6::Metamodel::ParametricRoleHOW.new
HOW2.compose

Как ясно видно из вывода, применение роли к метаклассу всегда работает для классов и работает только для $*PACKAGE.HOW с ролями. Использование $*PACKAGE вместо .package можно считать решением, но не тем, которое я действительно хотел бы использовать. (Хотя, если нет лучшего способа...)

Accessor

Я хотел бы также предоставить ленивую функциональность для личных атрибутов. Да, это будет доступно с self!bar только синтаксис, но это жертва, которую я готов принести. Проблема в том, что все примеры созданного на заказ средства доступа, которые я нашел до сих пор, используют Attribute.set_value() метод, который слишком низкоуровневый. Я хотел бы иметь что-то вроде этого:

 role MooishHOW {
     method compose ( Mu $class ) {
         my $accessor = $class.^add_private_method( 'bar1',
             method () is rw {
                 note self.WHO, ".bar1";
                 Proxy.new(
                     FETCH => -> $o {
                         $!bar1;
                     },
                     STORE => method ( $val ) {
                         note "Storing";
                         $!bar1 = $val;
                     }
                 );
             }
         );

         callsame;
     }
 }

 multi trait_mod:<is> (Attribute:D $attr, :$mooish!) {
     $attr.package.HOW does MooishHOW unless $attr.package.HOW ~~ MooishHOW;
 }

 class Foo {
     has $.bar is mooish;
     has $!bar1 is mooish;

     method to-bar1 {
         note "bar1 val:",self!bar1;
     }
 }

 my $inst = Foo.new;
 $inst.to-bar1; 

Но $!bar1 нотация не компилируется из-за области видимости (MooishRole). Есть ли у меня пропущенный трюк, который позволил бы ссылаться на закрытый атрибут self?

Хитрый

Возможно, можно сделать атрибут Proxy контейнер? Это значительно упростит общую логику реализации лени.

1 ответ

Решение

Я ответил на все мои вопросы, наконец достигнув цели и выпустив модуль AttrX:: Mooish.

Пока что ответ на первый вопрос: нет. $*PACKAGE в настоящее время единственный способ.

Второй вопрос: нет ответа, но окончательный код должен опираться на set_value() тем не мение.

Сложный случай оказался возможным: set_value() делает привязку атрибута к контейнеру, делая возможным привязку к Proxy объект. Не нужно жертвоприношений, частные атрибуты могут быть доступны напрямую, когда над ними работает лень.

Спасибо всем, ваши ответы позволили мне обойти некоторые грубые края!

Другие вопросы по тегам