【问题标题】:Apply a proxy to a variable (not an attribute) using traits使用特征将代理应用于变量(不是属性)
【发布时间】:2021-05-06 05:51:50
【问题描述】:

这个问题几乎与Apply a proxy using traits 重复。但是,该问题涉及将代理应用于属性,我想对变量做同样的事情。从乔纳森的回答中,我明白我

需要安排 Proxy 绑定到属性中,以便那里有一个 Proxy,而不是通常由类初始化逻辑创建的 Scalar 容器。

但是,我似乎无法成功绑定到变量:D,即使在编译时也是如此。 (包括 nqp::bind)。我将不胜感激任何正确方向的指针。

(理想情况下,我希望支持将变量/特征与赋值语法一起使用。在完美的世界中,我的语法如下:

my $thing is custom-proxy = 42;

结果是$thing 在代理中被容器化,但在标量中不是。但如果这不可能,我会通过:= 让它与绑定一起工作。

[编辑:在下面接受的答案的基础上,大部分可以使用以下代码执行此操作:


multi trait_mod:<is>(Variable \v, :$tom) {
    v.block.add_phaser(
        'ENTER',
        v.willdo(<-> $_ {
            $_ = Proxy.new:
                     STORE => -> $, $v { say "store $v" },
                     FETCH => { say "fetch!"; 42}
                }, 1))
}

这适用于未初始化为不同值的变量,或者适用于调用除第一个函数之外的函数时的 state 变量。

【问题讨论】:

    标签: raku rakudo


    【解决方案1】:

    你总是可以绑定的。

    my $actual-thing = 42;
    
    my $thing := Proxy.new(
        FETCH => anon method fetch () {
            say 'fetch';
            $actual-thing
        },
        STORE => anon method store ($new) {
            say 'store ',$new;
            $actual-thing = $new
        }
    );
    
    say $thing;
    $thing = 5;
    say $thing;
    

    目前导致以下结果。

    fetch
    fetch
    fetch
    fetch
    fetch
    fetch
    fetch
    42
    store 5
    fetch
    fetch
    fetch
    fetch
    fetch
    fetch
    fetch
    5
    

    (重复的FETCH 调用是一个已知的限制。)


    如果你想拥有类似的语法

    my $thing is custom-proxy = 42;
    

    你需要从

    multi trait_mod:<is> ( Variable:D \var, :$custom-proxy! ){
        …
    }
    

    问题是目前这样做需要很多我不具备的深入 Rakudo/nqp 知识。

    例如my $var is default('value')后面的代码看起来有点像这样:

    multi sub trait_mod:<is>(Variable:D $v, Mu :$default!) {
        my $var  := $v.var;
        my $what := $var.VAR.WHAT;
    
        my $descriptor;
        {
            $descriptor := nqp::getattr($var, $what.^mixin_base, '$!descriptor');
            CATCH {
                my $native = $v.native($what);
                …
            }
        }
        …
        $descriptor.set_default(nqp::decont($default));
    
        # make sure we start with the default if a scalar
        $var = $default if nqp::istype($what, Scalar);
    }
    

    为什么会有$what.^mixin_base
    我不知道。

    为什么$!descriptor 不能访问像$v.var.descriptor 这样的东西?
    我不知道。

    我们如何将 $v.var.VARScalar 更改为 Proxy
    我不知道。

    最后一个可行吗? (来自trait_mod:&lt;is&gt;) 我相当肯定答案是肯定的。

    【讨论】:

      【解决方案2】:

      我的 2d[1]

      我会通过 := 让它与绑定一起工作。

      sub custom-proxy is rw { Proxy.new: FETCH => { 42 }, STORE => { ... } }
      my $variable := custom-proxy;
      say $variable; # 42
      

      在一个完美的世界中,我的语法如下:

      my $thing is custom-proxy = 42;
      

      Aiui,这是@Larry 的意图。

      但是,您大概知道,如果使用 is 特征将类型(例如 role custom-proxy { ... })应用于 标量 变量(例如 my $variable is custom-proxy),那么编译器会发出编译时间错误信息 (is trait on $-sigil variable not yet implemented)。

      我似乎无法成功绑定到 Variable:D,即使在编译时也是如此

      首先,让我们澄清一下Variable 是什么,以及您需要成功绑定到什么:

      multi trait_mod:<is>(Variable \var, :$foo!) { say var.var.VAR.WHAT } # (Scalar)
      my $variable is foo;
      

      你可能认为你可以绑定到var。但是编译器传递的是一个左值,所以你不能改变它。

      您可能认为您可以绑定到var.var,这是Variable 的一个属性。 (我解释了Variable 是什么,它的var 属性,以及为什么我必须在上面的代码here 中写“varvarVAR!”。)

      您链接的 SO 显示了如何更改绑定到某个对象中属性的值:

      $a.set_build: -> \SELF, | {
        $a.set_value: SELF, Proxy.new:
          STORE => -> $, $val { say "store $val" },
          FETCH => { say "fetch!"; 42 }
      }
      

      那么也许您可以使用这种方法来更改Variable.var 属性?

      不幸的是,“设置构建逻辑”用于“绑定属性...在每个对象创建时”,(因此“您将覆盖任何初始默认值”)。

      所以我认为这种技术在这种情况下不会有帮助,因为Variable 及其.var 属性可能在Variable 传递给@987654344 时已经构建好了@特质。

      总之,虽然一个 trait is 在编译时被调用,但我认为它被称为 toolate 因为 var 属性已经被永久绑定了。 p>


      我的猜测是,更改 Raku(do) 以使 Variable.var 属性变为可写,或者使用元编程潜入 Variable 的公共 API 下以强制进行更改,这将是令人担忧的,不合理地使编译器的变量处理代码复杂化和/或将代码生成优化逻辑换成悲观逻辑。

      这可能是 @Larry 推测有一天会在标量变量上实现更受控制的 is type 的原因。

      脚注

      [1]我的两个(便士|狗狗币)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-08-04
        • 1970-01-01
        • 2016-11-19
        • 1970-01-01
        • 1970-01-01
        • 2015-06-30
        • 2022-11-04
        相关资源
        最近更新 更多