使用特征将代理应用于变量不是属性

问题描述

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

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

但是,即使在编译时,我似乎也无法成功绑定到 Variable: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 变量。

解决方法

您可以随时绑定。

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:<is> 内) 我相当肯定答案是肯定的。

,

我的二维[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 的意图。

但是,您大概知道,如果使用 role custom-proxy { ... } 特征将类型(例如 is)应用于 标量 变量(例如 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 属性,以及为什么我必须在上面的代码中写“varvarVAR!”,here。)

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

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

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

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

所以我不认为这种技术在这种情况下会有所帮助,因为 Variable 及其 .var 属性大概已经在 Variable传递给 is 特征。

总而言之,虽然在编译时调用 trait ,但我认为它被调用 太晚 因为 var 属性已经被永久绑定。


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

这可能是@Larry 推测的对标量变量更可控的 is type 有朝一日会实施的原因。

脚注

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...