私有属性的绑定:nqp :: bindattr vs:=

Vad*_*man 10 perl6 raku nqp

我试图找到绑定操作如何对属性起作用以及它与之如何不同nqp::bindattr.请考虑以下示例:

 class Foo {
     has @!foo;

     submethod TWEAK {
         my $fval = [<a b c>];
         use nqp;
         nqp::bindattr( nqp::decont(self), $?CLASS, '@!foo',
         #@!foo :=
             Proxy.new(
                 FETCH => -> $ { $fval },
                 STORE => -> $, $v { $fval = $v }
             )
         );
     }

     method check {
         say @!foo.perl;
     }
 }

 my $inst = Foo.new;
 $inst.check;
Run Code Online (Sandbox Code Playgroud)

它打印:

$["a", "b", "c"]

nqp::bindattr从注释中替换绑定运算符可以得到正确的输出:

["a", "b", "c"]

类似地,如果foo使用公共属性和访问器,则由于在访问器内发生去聚合,输出也是正确的.

我在我的AttrX::Mooish模块中使用类似的代码,其中使用:=会使实现过度复杂化.到目前为止,nqp::bindattr在上述问题出现之前,我做得很好.

我试图追查Rakudo的内部寻找:=实施但到目前为止没有任何成功.我会在这里询问有关如何模拟运算符或在源中查找其实现的建议.

Jon*_*ton 10

在我深入研究答案之前:本文中的大多数内容都是实现定义的,并且实现可以在将来以不同方式对它们进行不同的定义.

要找出在Rakudo Perl 6下编译的内容(天真),请使用--target=ast选项(perl6 --target=ast foo.p6).例如,绑定在:

class C {
    has $!a;
    submethod BUILD() {
        my $x = [1,2,3];
        $!a := $x
    }
}
Run Code Online (Sandbox Code Playgroud)

出来是:

                              - QAST::Op(bind)  :statement_id<7>
                                - QAST::Var(attribute $!a) <wanted> $!a
                                  - QAST::Var(lexical self) 
                                  - QAST::WVal(C) 
                                - QAST::Var(lexical $x)  $x
Run Code Online (Sandbox Code Playgroud)

@!a这里切换它时:

class C {
    has @!a;
    submethod BUILD() {
        my $x = [1,2,3];
        @!a := $x
    }
}
Run Code Online (Sandbox Code Playgroud)

出来是:

                              - QAST::Op(bind)  :statement_id<7>
                                - QAST::Var(attribute @!a) <wanted> @!a
                                  - QAST::Var(lexical self) 
                                  - QAST::WVal(C) 
                                - QAST::Op(p6bindassert) 
                                  - QAST::Op(decont) 
                                    - QAST::Var(lexical $x)  $x
                                  - QAST::WVal(Positional) 
Run Code Online (Sandbox Code Playgroud)

这里的decont指令是最大的区别,它将Proxy通过调用它来获取内容FETCH,因此容器化的原因就消失了.因此,你可以通过nqp::decont在周围插入来复制行为Proxy,尽管Proxy如果没有它就能得到正确的答案,那么就要回答那里正在做什么的问题!

双方:==采用案例分析汇编(即,通过看什么是左侧).:=仅适用于左侧有限范围的简单表达; 它是一个明确的低级别运营商.相比之下,如果案例分析没有提供更有效的发布方式,则会=回退到sub呼叫,尽管在大多数情况下它会更好地管理.

:=插入的情况分析a decont当目标是词汇或具有sigil的属性时,@或者%- 在Perl 6级别 - 具有绑定到@%没有意义的项目.使用nqp::bindattr是低于Perl 6语义的级别,因此可以Proxy使用它直接结束绑定.但是,它也违反了其他地方的期望.不要指望顺利(但似乎你不想这样做.)