Raku rebless 不再适用于继承类

Arn*_*mer 9 raku

此线程中给出的代码不再起作用:如何在 Perl 6 中重新启用对象?

我去年写了这段代码,然后它就起作用了。现在它没有:

class Person { ; }
class Woman is Person { ; }
my $tom = Person.new;
my $lisa = Woman.new;

say $tom.^name;  # -> Person
say $lisa.^name; # -> Woman

Metamodel::Primitives.rebless($tom, Woman);
# -> New type Woman for Person is not a mixin type
Run Code Online (Sandbox Code Playgroud)

错误消息没有意义,因为它应该与继承的类一起使用。至少是这样。

该文档没有帮助;https://docs.raku.org/routine/rebless

Jon*_*ton 11

它应该与继承的类一起工作

它从来不应该是那个将军。我设计了那个 API 并首先实现了它,它只是作为 mixin 的一个实现细节。

直到最近,它才成为语言规范测试套件的一部分——当它成为它的一部分时,它已经有了当前的、更严格的语义。出于性能原因,对它的约束很重要:当我们知道一个类型不能成为混合操作的目标时,我们可以将该对象的属性访问 JIT 编译成更简单的东西(我们在更改前的每个属性访问,现在只需在 mixin 目标类型上付费)。

可以通过使用 MOP 构造类来修改原始程序以使其工作。事实上,下面的程序并不完全是原始程序;为了展示如何在子类中作为匿名角色提供方法,我做了一个小调整,以避免过多的 MOP 样板。

class Person { method m() { "person" } }
constant Woman = do {
    my \w = Metamodel::ClassHOW.new_type(:is_mixin, :name<Woman>);
    w.^add_parent(Person);
    w.^add_role(role { method m() { "woman" } });
    w.^compose()
}
my $tom = Person.new;
my $lisa = Woman.new;

say $tom.^name;  # -> Person
say $lisa.^name; # -> Woman

say $tom.m; # person
Metamodel::Primitives.rebless($tom, Woman);
say $tom.m; # woman
Run Code Online (Sandbox Code Playgroud)

虽然这是对原始程序在语义上最直接的修复,但有一种更短的方法:使用类型对象but上的运算符Person生成一个混合类型并返回它,然后根据自己的喜好调整它的名称:

class Person { method m() { "person" } }
constant Woman = Person but role { method m() { "woman" } }
BEGIN Woman.^set_name('Woman');

my $tom = Person.new;
my $lisa = Woman.new;

say $tom.^name;  # -> Person
say $lisa.^name; # -> Woman

say $tom.m;
Metamodel::Primitives.rebless($tom, Woman);
say $tom.m;
Run Code Online (Sandbox Code Playgroud)

无论如何,这仅比原始多一行。


rai*_*iph 5

请参阅 jnthn 的答案,以获取有关究竟发生了rebless什么以及如何处理的权威讨论。

它有效......现在它没有......错误消息没有意义......它应该与继承的类一起工作......至少它是......文档没有帮助

对于那些有兴趣进一步讨论作为 Raku 编程语言和相关工件(如 Rakudo 编译器和docs.raku.org内容)基础工作的TDD方法的原则和实践的人来说,这个(超长!)答案可能值得一读.

此答案的结构是对 Arne 原始问题的特定部分以及他们针对此答案的早期版本所写的评论的特定回复。我的目的是让它对 Arne 更有用,同时,希望仍然对其他人有用。

Arne:此线程中给出的代码不再起作用:我如何在 Raku 中恢复对象?

我已经更新了该 SO 的已接受答案以链接到该 SO。

Arne:我去年写了这段代码,然后就奏效了。现在没有了

相关更改在2019 年 4 月的一次提交中进行了讨论,其中 jnthn 写道:

最近,作为rebless操作目标的类型开始需要显式创建为混合目标类型,以帮助优化。...

11 天前关闭 rakudo GH 问题“Rebless 自定义类型似乎不再起作用”的评论中,他写道:

您需要安排将is_mixin命名参数传递给ClassHOW.new_type...使用类语法无法做到这一点,因此还必须使用 MOP 组装 rebless 的目标类型。

(单击上面的链接以获取有关如何执行其建议的说明。)

这个问题也在它的工作中进一步讨论了......它突然没有......文档......应该记录下面的调用部分。

Arne:它应该与继承的类一起工作。至少是这样。

-的- [R epository Ø ˚F一个LL小号PEC牛逼的EST -决定了乐代码是应该做的。(该STROA ST可以读作小号upposedö峰)

20194 月的另一条消息中, jnthn 写道:

没有以前的规范Metamodel::Primitives.rebless。我已经添加了这个幽灵,所以现在有了。这意味着现在有一些可以预期工作的定义。

Rakudo 的行为由可执行测试套件规范这一事实是@Larry 确保 Raku 行为可靠[1]并具有深远影响[2]的方法的基本部分。

此更改对广泛使用的模块的影响

下面是这个变化对流行的 Inline::Perl5 模块的影响的快照。

2019 年 4 月,niner 开启了一个关于 rakudo GH 问题的影响Inline::Perl5,我在下面提取了niner 和 jnthn 之间交流的一些亮点。

(我省略了一些在原始上下文中很重要的内容,但在此 SO 的上下文中会分散注意力。请不要假设您完全理解了此摘录中的原始对话。如有疑问,请单击链接。 )

Niner: TBH 我在这里所做的可能总是有点可疑......甚至可能是......我可以摆脱[它]......虽然保持已经部署的 Inline::Perl5 版本启动和运行会很好.

jnthn:之前没有Metamodel::Primitives.rebless. 我已经添加了 [a] 幽灵所以现在有。这意味着现在有一些可以预期工作的定义,以及 Inline::Perl5 可以依赖的内容。

由于未知的命名参数被忽略,但:mixin在以前的 Rakudo 版本中不是必需的,那么就有可能制作一个新的 Inline::Perl5 版本,它可以在以前的 Rakudo 版本以及即将推出的版本上工作,所以至少可以有反向兼容。

我认为没有任何方法可以让现有的 Inline::Perl5 版本保持正常工作......

Niner:不幸的是,:mixin在这种情况下,传递无济于事,因为 rebless 是在通过Metamodel::Primitives.create_type. 子类使用正常的Perl6::ClassHOW.

我正在进行重大重构以首先摆脱 rebless hack。我正在重新打开这个问题,所以发布经理知道在 rakudo 的候选发布版本上没有可用的 Inline::Perl5。

jnthn:你使用 MOP 创建那个类吗?如果是这样,您可以传递:is_mixinPerl6::ClassHOW.new_type

Niner:不,是针对这种情况的:class Bar is Foo { }

帮助文档

在你写的这个答案下面的评论中:

我可以帮助文档部分

对我来说,这听起来像是对 SOQ 核心问题的非常恰当和有用的回应。我希望我们足够幸运,这一切都会发生。

如果这有帮助

Imo 你的技术写作非常出色,所以我希望你与其他参与改进它的人合作的最终结果将是一件美妙的事情。

docs.raku.org 内容的基本限制

我为这样一个看似简单的问题写了这个非常广泛的答案的其余部分,并在乔纳森回答后最初删除它后恢复它的很大一部分原因是讨论作为工作基础的TDD方法的原则和实践Raku 编程语言和相关工件,例如 Rakudo 编译器和docs.raku.org内容。

Aiui,事情应该如何在 Raku 中工作,它们如何在 Rakudo 中实际工作之间的理想关系,以及事情应该如何记录在docs.raku.org 上归结为:

  • 一切都必须被假定为永远受制于志愿者项目的基本性质;并且,在该限制内:

  • 烘焙中的 行为应该被记录,其他行为不应该被记录。

(考虑到可用的志愿者时间、兴趣和共识,偶尔会为记录适当 QA 的 Rakudo 的行为而设置例外,这些行为未包含在烤肉中。在目前的实践中,这似乎意味着 Rakudo 版本在已发布的 Rakudo Star 中的行为。)

无用的文档

该文档没有帮助

我认为这是一个公平的评论。考虑到所有因素,您编写问题时的文档没有帮助。

文档没用 [2018 年]

这是一个非常不同的说法。

当时没有烤入口覆盖rebless

如果在docs.raku.org页rebless 描述它的行为,因为它是在2018年,那么这将是有害无益,因为它会错误地认为当时的行为得到了支持。实际上,如果没有合理的前景,核心开发人员将恢复 2018 年的行为,它就有可能在 Rakudo 的未来版本中被打破。这确实发生了:它自 2018 年以来不受支持的行为确实中断了,并且没有恢复。

因此,鉴于对 docs.raku.org 中哪些属于哪些不属于的共识(见上文),其rebless页面可以做的最有帮助的事情是要么根本不记录rebless,要么更好,包括一个页面,但确保它也没有说明它的行为。情况是这样的:页面确实存在;没有直接帮助;这可以说总比没有好。

(很容易想象事情会变得更好。例如,如果在最新的 Rakudo Star 的 Rakudo 版本中记录函数的页面包含记录与该函数相关的测试覆盖率状态的百分比怎么办?0% 可以立即提示读者意识到该功能没有被烤覆盖。也就是说,虽然这个文档功能很容易想象,但谁来实现它?同样容易想象它可能需要一个日历年或更长时间的勤奋工作和协作以有效地实施和部署,而人们认为其他事情更重要。)

它有效......突然没有......文档......应该记录呼叫

有效

这是“运气”它起作用了。

它突然不工作了

因为乐堂得到了改进。

文档......应该记录调用

如前所述,aiui 当前社区共识和/或工作实践是:文档应该记录调用的特定版本,即最新 Rakudo Star 中 Rakudo 版本的烘焙行为;并且可以记录其他版本中的行为。

而不是指别的东西

Aiui,目前的共识和/或工作实践是,如果志愿者认为有必要立即进行更改以反映某些人可能认为“弱”的文档贡献,例如一些简短、匆忙编写的内容和/或文档之外的链接,可以引入用户提出的一些担忧(例如这个 SO),并且做出“弱”更改总比什么都不做要好。你当然可以做一个 PR 来改进它(或者,如果你真的觉得一个改变太“弱”了,它会让事情变得更糟,你可以恢复它)。

根据我的统计,对 2019.11 更改的引用是 7 个月

(据我所知,这也是类似的情况,尽管我见过一个声称是 2019.03.1 的编译器,但行为也有相同的中断。[3]

我认为 JJ 对文档进行了更改,而他只是误解了 jnthn 关于如何适应更改的评论。我目前认为它总比没有好,但期待你更新它。:)

脚注

[1]在拉里在他 2000 年的“洋葱国度”演讲中首次宣布导致 Raku 的项目后几分钟说了以下内容:

问:[乐]会有规格吗?

Larry:我们特别想强调的......也许不是[语言设计]规范,而是开发我们当前的回归测试......成为语言实际含义的验证测试,实际上出去探索所有角落和缝隙说,“这是[Raku],这不是[Raku],”然后我们实际上有一个机器可读的规范。对我来说,这实际上比人类可读事物中的措辞要重要得多。

[2]当然,只有当它的测试足以满足用户的需求时,烘焙才会对给定的用户有效。Arne 的问题展示了覆盖范围的漏洞是多么令人惊讶。有关这些漏洞在 2018 年的讨论,请参阅规范、版本控制、更改和……破损。好消息是,烤只是用 Raku 编写的大量单元测试,用于测试具有特定值的表达式或构造是否执行特定的操作。因此,个人或公司很容易贡献新的测试来提高测试覆盖率。而且这一切都在版本控制 (git) 之下,因此自定义下游标签、分支和分支是可行的、可持续的和可管理的。(事实上​​,这就是管理新语言版本(ChristmasDiwaliEid(?) 等)的方式。)

[3]我见过企图rebless使用正则产生了新的newclass is oldclass语法都工作(我的笔记本电脑)不工作(上repl.it)使用的编译器,声称是2019.03.1。(大概 repl.it 安装了一个版本的编译器源代码,或从它编译的二进制文件,在编译器的版本更新到 后不久从主头中获取2019.03.1,并进行了重大更改。我注意到 repl.it 没有' t 公开了他们的在线 raku repl——我是偶然发现的——所以这种情况没有什么不妥,但它加强了我对$RAKU.compiler.verbose-config我刚刚链接的工作/损坏输出中使用的方法的需求。)