性状中的混合角色显然不起作用

jjm*_*elo 5 traits perl6

这个例子是采取roast,虽然它已经有8年了:

role doc { has $.doc is rw }

multi trait_mod:<is>(Variable $a, :$docced!) {
    $a does doc.new(doc => $docced);
}

my $dog is docced('barks');
say $dog.VAR;
Run Code Online (Sandbox Code Playgroud)

这将返回Any,而不会混入任何角色。尽管特质不会出错,但显然没有办法进入“ doc”部分。任何的想法?

rai*_*iph 5

(此答案基于@guifa的答案和JJ的评论。)

在可变特征中使用的成语本质上是$var.var.VAR

大声说出这听起来很有趣,但这似乎也很疯狂。不是,但它至少需要解释,也许还需要某种形式的认知/句法缓解。

这是如何理解的简短版本:

  • $var之所以将其作为trait参数的名称是有意义的,因为它绑定到了变量Variable编译器视点。

  • .var给定编译器的视图,需要访问用户的变量视图。

  • 如果变量是Scalar那么.VAR需要以及得到变量,而不是它包含的价值。(如果不是,则无害Scalar。)

松一口气?

我将在一个月中更详细地说明上述内容,但首先,如何缓解一下呢?

也许我们可以引入一种新的Variable方法.var.VAR。但是,除非该方法的名称如此好,以至于根本不需要$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
Run Code Online (Sandbox Code Playgroud)

更长的解释 $var.var.VAR

但是$v已经是一个变量了。为什么有这么多varVARS'

确实。$v绑定到Variable该类的实例。这还不够吗?

不,因为Variable

  • 用于在编译变量存储有关变量的元数据。(也许它应该被称为?只是在开玩笑。在特征签名上看起来不错,并且更改其名称也不会阻止我们继续使用和解释该习语。)Metadata-About-A-Variable-Being-CompiledVariable$var.var.VAR

  • 不是我们要寻找的机器人。我们需要用户对变量的看法。已经被声明和编译的代码,然后被用作用户代码的一部分。(例如,$dog在该行say $dog...。即使有BEGIN say $dog...,所以它跑在编译时,$dog仍然指的是绑定到一个user's眼视图容器或价值的象征。它不会指Variable这仅仅是实例编译器变量相关数据的直观视图。)

  • 使编译器和编写特质的人更加轻松。但这要求特征编写者访问变量的用户视角,以访问或更改用户的视角。该用户视线.varVariable商店的属性。(我注意到烘烤测试的.container属性已被省略,现在已被重命名.var。我的猜测是这是因为变量可能绑定到不可变值而不是容器,因此该名称.container被认为具有误导性。)

那么,我们如何到达$var.var.VAR

让我们从原始代码的变体开始,然后继续。我将从切换$dog@dog.VARsay行中删除:

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

几乎可行。一个微小的变化,它的工作原理是:

multi trait_mod:<is>(Variable $a, :$docced!) {
  $a.var does role { has $.doc = $docced }
}

my @dog is docced('barks');
say @dog.doc; # barks
Run Code Online (Sandbox Code Playgroud)

所有我做的就是添加一个.var... does role ...线。在您的原始代码中,该行正在修改变量的编译器视图,即Variable绑定到的对象$a。它不会修改变量的用户视图,即Array绑定到@dog

据我所知,现在对于数组和哈希之类的复数容器,一切都可以正常工作:

@dog[1] = 42;
say @dog;     # [(Any) 42]
say @dog.doc; # barks
Run Code Online (Sandbox Code Playgroud)

但是,当我们尝试使用Scalar变量时:

my $dog is docced('barks');
Run Code Online (Sandbox Code Playgroud)

我们得到:

Cannot use 'does' operator on a type object Any.
Run Code Online (Sandbox Code Playgroud)

这是因为.var无论用户的眼睛视图变量通常返回什么,它都会返回。有了,Array你得到了Array。但是有了a,Scalar您将获得Scalar包含的值。(这是P6的基本方面。它很好用,但是您必须在这种情况下知道它。)

因此,要使它再次显示正常工作,我们还必须添加一对夫妇.VAR。对于除以外的任何Scalar一个.VAR是“无操作”,所以它没有伤害比其他情况下,Scalar将其添加:

multi trait_mod:<is>(Variable $a, :$docced!) {
  $a.var.VAR does role { has $.doc = $docced }
}
Run Code Online (Sandbox Code Playgroud)

现在,这种Scalar情况似乎也起作用了:

my $dog is docced('barks');
say $dog.VAR.doc; # barks
Run Code Online (Sandbox Code Playgroud)

(我不得不重新引入.VARsay出于同样的原因,我不得不把它添加到行$a.var.VAR ...线。)

如果一切都好,那将是答案的结尾。

一个错误

但是有些东西坏了。如果我们尝试初始化Scalar变量:

my $dog is docced('barks') = 42;
Run Code Online (Sandbox Code Playgroud)

我们会看到:

Cannot assign to an immutable value
Run Code Online (Sandbox Code Playgroud)

正如@guifa所指出的,我在不久前偶然发现

Scalar带有mixin的似乎不再成功用作容器,并且分配失败。在我看来,这目前似乎是一个错误。