Написание признака атрибута
Я собираюсь выбрать, какой язык использовать для нового проекта: 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
объект. Не нужно жертвоприношений, частные атрибуты могут быть доступны напрямую, когда над ними работает лень.
Спасибо всем, ваши ответы позволили мне обойти некоторые грубые края!