(此答案基于@guifa 的回答和 JJ 的评论。)
用于可变特征的习语本质上是$var.var.VAR。
虽然大声说出来听起来很有趣,但看起来也很疯狂。不是,但它至少需要解释,并且也许需要某种认知/句法缓解。
以下是如何理解它的简要版本:
$var 作为 trait 参数的名称是有意义的,因为它绑定到 Variable,编译器的视角变量视图。
.var 需要在给定编译器视图的情况下访问变量的用户视图视图。
如果变量是Scalar,则需要.VAR以及来获取变量而不是它包含的值。 (如果不是 Scalar 也无妨。)
松了一口气?
我会在一月内更详细地解释上述内容,但首先,缓解一下如何?
也许我们可以引入一个新的Variable 方法来处理.var.VAR。但是 imo 这将是一个错误,除非该方法的名称非常好,它基本上消除了在此答案的下一部分中对 $var.var.VAR 咒语解释的需要。
但我怀疑这样的名字是否存在。我想出的每一个名字都在某种程度上让事情变得更糟。即使我们想出了一个完美的名字,它也几乎不值得。
我对您原始示例的复杂性感到震惊。有一个 is 特征调用 does 特征。因此,也许需要一个程序来抽象这种复杂性和$var.var.VAR。但是无论如何,有一些现有的方法可以降低这种双重特征的复杂性,例如:
role doc[$doc] { has $.doc is rw = $doc}
my $dog does doc['barks'];
say $dog.doc; # barks
$var.var.VAR的加长解释
但是$v 已经是一个变量。为什么会有这么多var 和VARs?
确实如此。 $v 绑定到 Variable 类的实例。这还不够吗?
不,因为Variable:
-
用于存储元数据关于一个变量在编译时。 (也许它应该被称为Metadata-About-A-Variable-Being-Compiled?开个玩笑。Variable 在特征签名中看起来不错,并且更改它的名称不会阻止我们需要使用和解释$var.var.VAR 习语。)
李>
不是我们要找的机器人。我们想要一个变量的用户视角。一个已被声明和编译,然后被用作用户代码的一部分。 (例如,$dog 在 say $dog... 行中。即使它是 BEGIN say $dog...,所以它在编译时运行,$dog仍然引用一个绑定到用户视角容器或值。它不会引用 Variable 实例,它只是与变量相关数据的编译器视角。)
使编译器和编写特性的人的生活更轻松。但它要求特征编写者访问变量的用户视图以访问或更改用户视图。 Variable 的 .var 属性存储该用户的视图。 (我注意到烘烤测试有一个您省略的.container 属性。现在显然已重命名为.var。我的猜测是这是因为变量可能绑定到不可变值而不是容器,所以名称.container被认为具有误导性。)
那么,我们如何到达$var.var.VAR?
让我们从原始代码的变体开始,然后继续前进。我将从$dog 切换到@dog 并从say 行中删除.VAR:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a does role { has $.doc = $docced }
}
my @dog is docced('barks');
say @dog.doc; # No such method 'doc' for invocant of type 'Array'
这几乎有效。一个微小的变化,它的工作原理:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var does role { has $.doc = $docced }
}
my @dog is docced('barks');
say @dog.doc; # barks
我所做的只是将.var 添加到... does role ... 行。在您的原始文件中,该行正在修改变量的编译器视图,即绑定到$a 的Variable 对象。它不会修改用户对变量的看法,即绑定到@dog 的Array。
据我所知,现在一切都适用于数组和散列等多个容器:
@dog[1] = 42;
say @dog; # [(Any) 42]
say @dog.doc; # barks
但是当我们尝试使用Scalar 变量时:
my $dog is docced('barks');
我们得到:
Cannot use 'does' operator on a type object Any.
这是因为.var 返回用户眼视图变量通常返回的任何内容。使用Array,您将获得Array。但是使用Scalar 你会得到Scalar 包含的值。 (这是 P6 的一个基本方面。它工作得很好,但你必须在这些场景中了解它。)
所以要让这个显示再次工作,我们还必须添加一对.VAR。对于 Scalar 以外的任何内容,.VAR 是“无操作”,因此添加它对 Scalar 以外的情况没有任何危害:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var.VAR does role { has $.doc = $docced }
}
现在Scalar 的情况似乎也有效:
my $dog is docced('barks');
say $dog.VAR.doc; # barks
(我不得不在say 行中重新引入.VAR,原因与我必须将其添加到$a.var.VAR ... 行中的原因相同。)
如果一切顺利,这将是这个答案的结束。
一个错误
但是有些东西坏了。如果我们尝试初始化 Scalar 变量:
my $dog is docced('barks') = 42;
我们会看到:
Cannot assign to an immutable value
正如@guifa 所说,I stumbled on a while back:
似乎带有 mixin 的 Scalar 不再成功地用作容器并且分配失败。在我看来,这目前看起来像是一个错误。