写一个属性特征

Vad*_*man 9 perl6 mop

我即将选择用于新项目的语言: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;
 }
Run Code Online (Sandbox Code Playgroud)

脚本的输出如下:

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
Run Code Online (Sandbox Code Playgroud)

从输出中可以清楚地看到,将角色应用于元类始终适用于类,仅适用于$*PACKAGE.HOW角色.使用$*PACKAGE而不是.package可以被认为是一种解决方案,但不是我真正想要使用的解决方案.(但是,如果没有更好的方法......)

访问

我也想为私有属性提供延迟功能.是的,这将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; 
Run Code Online (Sandbox Code Playgroud)

$!bar1由于范围(MooishRole),符号不能编译.我是否缺少一个可以引用私有属性的技巧self

棘手的一个

也许可以将属性设置为Proxy容器?这将大大简化懒惰实现的整体逻辑.

Vad*_*man 4

我已经回答了我所有的问题,最终实现了目标并发布了AttrX::Mooish模块。

到目前为止,第一个问题的答案是:不。$*PACKAGE目前是唯一的办法。

第二个问题:没有答案,但是最终的代码set_value()无论如何都要依赖。

棘手的问题恰好是可能的:set_value()将属性绑定到容器是否可以绑定到Proxy。无需做出牺牲,可以直接访问私有属性,并对其进行惰性处理。

谢谢大家,你们的回答让我解决了一些粗糙的问题!