Raku rebless 不再适用于 inherited 类
Raku rebless doesn't work with inherited classes anymore
此线程中给出的代码不再有效:
这段代码是我去年写的,当时就成功了。现在没有了:
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
错误消息没有意义,因为它应该与继承 类 一起使用。
至少是。
请参阅 jnthn 的回答,了解关于 rebless
究竟发生了什么以及如何应对的权威讨论。
it worked ... Now it doesn't .. The error message doesn't make sense ... it is supposed to work with inherited classes ... At least it was ... The documentation is not helpful
对于那些有兴趣进一步讨论 TDD approach that underlies work on the Raku programming language and related artifacts such as the Rakudo compiler and docs.raku.org 内容的原则和实践的人来说,这个(超长!)答案可能值得一读。
此答案的结构是对 Arne 的原始问题的特定部分以及他们为响应此答案的早期版本而写的评论的特定回复。我的目的是让它对 Arne 更有用,同时希望对其他人仍然有用。
Arne: The code given in this thread doesn't work anymore:
我已将该 SO 的已接受答案更新为 link 到此 SO。
Arne: I wrote this piece of code last year, and it worked then. Now it doesn't
相关更改在 an April 2019 commit 中进行了讨论,其中 jnthn 写道:
Recently, types that were the target of a rebless
operation started
needing to be created explicitly as mixin target types, to assist
optimization. ...
在a comment 11 days ago closing rakudo GH issue "Rebless to a custom type no longer seems to work"中,他写道:
You'll need to arrange to have the is_mixin
named argument passed to ClassHOW.new_type
... There's no way to do that with the class syntax, thus the target type of the rebless shall have to be assembled using the MOP also.
(单击上面的 link 以获取有关如何执行其建议的说明。)
这个问题在 它起作用了......它突然没有......文档......应该记录下面的调用 部分。
Arne: it is supposed to work with inherited classes. At least it was.
roast -- r存储库of all spec tests -- 确定 Raku 代码应该做什么。 (roast的st可以读作 s假设tos.)
在 another April 2019 message jnthn 中写道:
There was no previous spec for Metamodel::Primitives.rebless
. I've added this spectest so that now there is. This means there's now some definition of what can be expected to work.
Rakudo 的行为由可执行测试套件规范这一事实是@Larry 确保 Raku 行为可靠的方法的基本组成部分[1] 并且具有深远的影响[2].
此更改对广泛使用的模块的影响
下面简要介绍了这一变化对流行的 Inline::Perl5 模块的影响。
2019年4月,niner开通了a rakudo GH issue on the impact on Inline::Perl5
,下面我摘录了niner和jnthn交流的一些亮点
(我省略了一些在原始上下文中很重要的东西,但在这个 SO 的上下文中会分散注意力。请不要假设你有 完整 的理解此摘录中的原始对话。如有疑问,请单击 link。)
niner: TBH what I do here has probably always been kinda fishy ... Could even be that ... I can get rid of [it] ... Would be nice though to keep already deployed Inline::Perl5 versions up and running.
jnthn: There was no previous spec for Metamodel::Primitives.rebless
. I've added [a] spectest so that now there is. This means there's now some definition of what can be expected to work, and which Inline::Perl5 can rely on.
Since unknown named parameters are ignored, but :mixin
was not required on previous Rakudo versions, then it would be possible to make a new Inline::Perl5 release that can work on previous Rakudo versions as well as the upcoming one, so there can at least be back-compat.
I don't think there's any way of keeping things working for existing Inline::Perl5 versions ...
niner: Unfortunately passing :mixin
doesn't help in this case as the rebless is done on a subclass of the one created via Metamodel::Primitives.create_type
. The subclass uses the normal Perl6::ClassHOW
.
I'm working on a major refactor to get rid of the rebless hack in the first place. I'm reopening this issue so the release manager is aware of there being no working Inline::Perl5 on rakudo's release candidate.
jnthn: Do you create that class using the MOP? You can pass :is_mixin
to Perl6::ClassHOW.new_type
if so.
niner: No, it's for this situation: class Bar is Foo { }
帮助处理文档
在您所写的此答案下方的评论中:
I can help with the documentation part
在我看来,这是对您 SOQ 核心问题的非常恰当和有用的回应。我希望我们足够幸运,能够实现这一目标。
if that helps
我觉得你的技术写作非常棒,所以我希望你与其他参与改进它的人一起工作的最终结果会是一件很棒的事情。
docs.raku.org 内容的基本限制
我为这样一个看似简单的问题写了这个非常广泛的答案的其余部分,并在 Jonathan 回答后最初删除它后恢复它的很大一部分原因是讨论
TDD approach that underlies work on the Raku programming language and related artifacts such as the Rakudo compiler and docs.raku.org 内容的原则和实践。
Aiui,事物在 Raku 中的工作方式与它们在 Rakudo 中的实际工作方式之间的理想关系,以及事物在 docs.raku.org 上的记录方式归结为:
(考虑到可用的志愿者时间、兴趣和共识,有时会例外记录未被 roast 涵盖的适当 QA'd Rakudo 的行为。在目前的实践中,这似乎意味着 Rakudo 版本的行为在发布了 Rakudo Star。)
无用的文档
The documentation is not helpful
我认为这是一个公平的评论。考虑到所有因素,您编写问题时的文档没有帮助。
the documentation was useless [in 2018]
这是一个非常不同的说法。
当时没有涵盖 rebless
的烤条目。
如果 rebless
上的 docs.raku.org 页面 描述了它在 2018 年的行为,那么情况会 更糟比 useless 因为它会错误地暗示当时的当前行为得到支持。实际上,在没有合理前景的情况下,它有可能在 Rakudo 的未来版本中被破坏,核心开发人员将恢复 2018 年的行为。这确实发生了:它从 2018 年开始不受支持的行为确实中断了,并且没有恢复。
因此,考虑到关于什么属于 docs.raku.org 什么不属于(见上文)的共识,其 rebless
页面可以做的最有帮助的事情是要么不记录 rebless
,或者最好为它包含一个页面,但要确保它没有描述它的行为。情况是这样的:该页面确实存在;没有直接帮助;这可以说总比没有好。
(很容易想象事情会变得更好。例如,如果在最新的 Rakudo Star 的 Rakudo 版本中,记录函数的页面包含一个百分比来记录与该函数相关的测试覆盖率的状态?0%可以立即让 reader 意识到 roast 未涵盖该功能。也就是说,虽然此文档功能很容易想象,但谁将实施它?同样容易想象,可能需要一年或更长时间的辛勤工作和协作才能有效地实施和部署,而且人们认为其他事情更重要。)
它起作用了……它突然不起作用了……文档……应该记录调用
it worked
成功是“运气”。
it suddenly didn't work anymore
因为Rakudo得到了改进。
the documentation ... should document the call
如前所述,aiui当前社区共识and/or工作实践是:文档SHOULD文档特定版本的调用,即roast在最新Rakudo Star中对Rakudo版本的行为;并且可以记录其他版本中的行为。
and not refer to something else
Aiui,目前的共识 and/or 工作实践是一些人可能认为“弱”的文档贡献,例如一些简短、匆忙写的内容 and/or links 在文档之外,如果志愿者认为有必要立即进行更改以反映用户提出的某些问题(例如本 SO),并且进行“弱”更改总比什么都不做要好,则可以引入。你当然可以做一个 PR 来改进它(或者如果你真的觉得一个变化太“弱”以至于让事情变得更糟,就恢复它)。
the reference to changes in 2019.11 is 7 months off by my count
(根据我的统计,这也是类似的情况,尽管我看到一个编译器声称是 2019.03.1,其行为也有相同的中断。[3])
我认为 JJ 更改了文档,他只是误解了 jnthn 关于如何适应更改的评论。我目前认为它总比没有好,但期待您对其进行更新。 :)
脚注
[1] 在 Larry 于 his 2000 "State of the Onion" speech 首次宣布导致 Raku 的项目几分钟后说了以下内容:
Question: Will [Raku] have specs?
Larry: what we particularly want to stress ... is not perhaps so much the [language design] spec as developing our current regression test ... into a validation test of what the language actually means and actually go out and explore all the nooks and crannies and say, “This is [Raku], this is not [Raku],” and then we actually have a machine-readable spec. And to me that’s actually a lot more important than what the verbiage in the human readable thing says.
[2] 当然,只有在测试足以满足用户需求的情况下,roast 才会对特定用户产生良好效果。 Arne 的问题展示了覆盖范围中的漏洞是多么令人惊讶。有关这些漏洞在 2018 年的讨论,请参阅 On Specs, Versioning, Changes, and… Breakage。好消息是,roast 只是用 Raku 编写的大量单元测试,用于测试具有特定值的表达式或结构是否执行特定操作。因此,个人或公司很容易贡献新的测试来提高测试覆盖率。而且这一切都在版本控制下 (git),因此自定义下游标签、分支和分叉是可行的、可持续的和可管理的。 (事实上,这就是新语言版本(Christmas
、Diwali
、Eid
(?) 等)的管理方式。)
[3] 我看到有人试图重新祝福使用常规 newclass is oldclass
语法创建的新 class work (on my laptop) and not work (on repl.it) 使用编译器自称是 2019.03.1
。 (据推测 repl.it 安装了一个版本的编译器源代码,或从它编译的二进制文件,在编译器版本更新到 2019.03.1
后不久从主头上获取,并进行了重大更改。我请注意,repl.it 尚未公布他们的在线 raku repl——我是偶然发现的——所以这种情况并没有什么不妥,但它让我更加需要 $RAKU.compiler.verbose-config
在 worked/broken 输出我刚刚 linked.)
it is supposed to work with inherited classes
它从来不应该是那样的将军。我首先设计了 API 并实现了它,它只是作为 mixins 的实现细节。
直到最近,它还不是语言规范测试套件的一部分 - 当它成为其中的一部分时,它已经拥有了当前的、更具限制性的语义。出于性能原因,对它的约束很重要:当我们知道一个类型不是可以作为混合操作目标的类型时,我们可以 JIT 编译对该对象的属性访问更简单(我们支付了额外的条件移动更改之前的每个属性访问,现在只需要在 mixin 目标类型上支付它)。
可以通过使用 MOP 构造 class 来修改原始程序以使其工作。事实上,下面的程序并不完全是原始程序;为了展示如何在 subclass 中提供方法作为匿名角色,我做了一个小调整,以避免过多的 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
虽然这是对原始程序最直接的语义修复,但还有一个更短的方法:在 Person
类型对象上使用 but
运算符来生成混合类型和 return,然后根据自己的喜好调整其名称:
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;
反正就是比原来多了一行。
此线程中给出的代码不再有效:
这段代码是我去年写的,当时就成功了。现在没有了:
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
错误消息没有意义,因为它应该与继承 类 一起使用。 至少是。
请参阅 jnthn 的回答,了解关于 rebless
究竟发生了什么以及如何应对的权威讨论。
it worked ... Now it doesn't .. The error message doesn't make sense ... it is supposed to work with inherited classes ... At least it was ... The documentation is not helpful
对于那些有兴趣进一步讨论 TDD approach that underlies work on the Raku programming language and related artifacts such as the Rakudo compiler and docs.raku.org 内容的原则和实践的人来说,这个(超长!)答案可能值得一读。
此答案的结构是对 Arne 的原始问题的特定部分以及他们为响应此答案的早期版本而写的评论的特定回复。我的目的是让它对 Arne 更有用,同时希望对其他人仍然有用。
Arne: The code given in this thread doesn't work anymore:
我已将该 SO 的已接受答案更新为 link 到此 SO。
Arne: I wrote this piece of code last year, and it worked then. Now it doesn't
相关更改在 an April 2019 commit 中进行了讨论,其中 jnthn 写道:
Recently, types that were the target of a
rebless
operation started needing to be created explicitly as mixin target types, to assist optimization. ...
在a comment 11 days ago closing rakudo GH issue "Rebless to a custom type no longer seems to work"中,他写道:
You'll need to arrange to have the
is_mixin
named argument passed toClassHOW.new_type
... There's no way to do that with the class syntax, thus the target type of the rebless shall have to be assembled using the MOP also.
(单击上面的 link 以获取有关如何执行其建议的说明。)
这个问题在 它起作用了......它突然没有......文档......应该记录下面的调用 部分。
Arne: it is supposed to work with inherited classes. At least it was.
roast -- r存储库of all spec tests -- 确定 Raku 代码应该做什么。 (roast的st可以读作 s假设tos.)
在 another April 2019 message jnthn 中写道:
There was no previous spec for
Metamodel::Primitives.rebless
. I've added this spectest so that now there is. This means there's now some definition of what can be expected to work.
Rakudo 的行为由可执行测试套件规范这一事实是@Larry 确保 Raku 行为可靠的方法的基本组成部分[1] 并且具有深远的影响[2].
此更改对广泛使用的模块的影响
下面简要介绍了这一变化对流行的 Inline::Perl5 模块的影响。
2019年4月,niner开通了a rakudo GH issue on the impact on Inline::Perl5
,下面我摘录了niner和jnthn交流的一些亮点
(我省略了一些在原始上下文中很重要的东西,但在这个 SO 的上下文中会分散注意力。请不要假设你有 完整 的理解此摘录中的原始对话。如有疑问,请单击 link。)
niner: TBH what I do here has probably always been kinda fishy ... Could even be that ... I can get rid of [it] ... Would be nice though to keep already deployed Inline::Perl5 versions up and running.
jnthn: There was no previous spec for
Metamodel::Primitives.rebless
. I've added [a] spectest so that now there is. This means there's now some definition of what can be expected to work, and which Inline::Perl5 can rely on.
Since unknown named parameters are ignored, but
:mixin
was not required on previous Rakudo versions, then it would be possible to make a new Inline::Perl5 release that can work on previous Rakudo versions as well as the upcoming one, so there can at least be back-compat.
I don't think there's any way of keeping things working for existing Inline::Perl5 versions ...
niner: Unfortunately passing
:mixin
doesn't help in this case as the rebless is done on a subclass of the one created viaMetamodel::Primitives.create_type
. The subclass uses the normalPerl6::ClassHOW
.
I'm working on a major refactor to get rid of the rebless hack in the first place. I'm reopening this issue so the release manager is aware of there being no working Inline::Perl5 on rakudo's release candidate.
jnthn: Do you create that class using the MOP? You can pass
:is_mixin
toPerl6::ClassHOW.new_type
if so.
niner: No, it's for this situation:
class Bar is Foo { }
帮助处理文档
在您所写的此答案下方的评论中:
I can help with the documentation part
在我看来,这是对您 SOQ 核心问题的非常恰当和有用的回应。我希望我们足够幸运,能够实现这一目标。
if that helps
我觉得你的技术写作非常棒,所以我希望你与其他参与改进它的人一起工作的最终结果会是一件很棒的事情。
docs.raku.org 内容的基本限制
我为这样一个看似简单的问题写了这个非常广泛的答案的其余部分,并在 Jonathan 回答后最初删除它后恢复它的很大一部分原因是讨论 TDD approach that underlies work on the Raku programming language and related artifacts such as the Rakudo compiler and docs.raku.org 内容的原则和实践。
Aiui,事物在 Raku 中的工作方式与它们在 Rakudo 中的实际工作方式之间的理想关系,以及事物在 docs.raku.org 上的记录方式归结为:
(考虑到可用的志愿者时间、兴趣和共识,有时会例外记录未被 roast 涵盖的适当 QA'd Rakudo 的行为。在目前的实践中,这似乎意味着 Rakudo 版本的行为在发布了 Rakudo Star。)
无用的文档
The documentation is not helpful
我认为这是一个公平的评论。考虑到所有因素,您编写问题时的文档没有帮助。
the documentation was useless [in 2018]
这是一个非常不同的说法。
当时没有涵盖 rebless
的烤条目。
如果 rebless
上的 docs.raku.org 页面 描述了它在 2018 年的行为,那么情况会 更糟比 useless 因为它会错误地暗示当时的当前行为得到支持。实际上,在没有合理前景的情况下,它有可能在 Rakudo 的未来版本中被破坏,核心开发人员将恢复 2018 年的行为。这确实发生了:它从 2018 年开始不受支持的行为确实中断了,并且没有恢复。
因此,考虑到关于什么属于 docs.raku.org 什么不属于(见上文)的共识,其 rebless
页面可以做的最有帮助的事情是要么不记录 rebless
,或者最好为它包含一个页面,但要确保它没有描述它的行为。情况是这样的:该页面确实存在;没有直接帮助;这可以说总比没有好。
(很容易想象事情会变得更好。例如,如果在最新的 Rakudo Star 的 Rakudo 版本中,记录函数的页面包含一个百分比来记录与该函数相关的测试覆盖率的状态?0%可以立即让 reader 意识到 roast 未涵盖该功能。也就是说,虽然此文档功能很容易想象,但谁将实施它?同样容易想象,可能需要一年或更长时间的辛勤工作和协作才能有效地实施和部署,而且人们认为其他事情更重要。)
它起作用了……它突然不起作用了……文档……应该记录调用
it worked
成功是“运气”。
it suddenly didn't work anymore
因为Rakudo得到了改进。
the documentation ... should document the call
如前所述,aiui当前社区共识and/or工作实践是:文档SHOULD文档特定版本的调用,即roast在最新Rakudo Star中对Rakudo版本的行为;并且可以记录其他版本中的行为。
and not refer to something else
Aiui,目前的共识 and/or 工作实践是一些人可能认为“弱”的文档贡献,例如一些简短、匆忙写的内容 and/or links 在文档之外,如果志愿者认为有必要立即进行更改以反映用户提出的某些问题(例如本 SO),并且进行“弱”更改总比什么都不做要好,则可以引入。你当然可以做一个 PR 来改进它(或者如果你真的觉得一个变化太“弱”以至于让事情变得更糟,就恢复它)。
the reference to changes in 2019.11 is 7 months off by my count
(根据我的统计,这也是类似的情况,尽管我看到一个编译器声称是 2019.03.1,其行为也有相同的中断。[3])
我认为 JJ 更改了文档,他只是误解了 jnthn 关于如何适应更改的评论。我目前认为它总比没有好,但期待您对其进行更新。 :)
脚注
[1] 在 Larry 于 his 2000 "State of the Onion" speech 首次宣布导致 Raku 的项目几分钟后说了以下内容:
Question: Will [Raku] have specs?
Larry: what we particularly want to stress ... is not perhaps so much the [language design] spec as developing our current regression test ... into a validation test of what the language actually means and actually go out and explore all the nooks and crannies and say, “This is [Raku], this is not [Raku],” and then we actually have a machine-readable spec. And to me that’s actually a lot more important than what the verbiage in the human readable thing says.
[2] 当然,只有在测试足以满足用户需求的情况下,roast 才会对特定用户产生良好效果。 Arne 的问题展示了覆盖范围中的漏洞是多么令人惊讶。有关这些漏洞在 2018 年的讨论,请参阅 On Specs, Versioning, Changes, and… Breakage。好消息是,roast 只是用 Raku 编写的大量单元测试,用于测试具有特定值的表达式或结构是否执行特定操作。因此,个人或公司很容易贡献新的测试来提高测试覆盖率。而且这一切都在版本控制下 (git),因此自定义下游标签、分支和分叉是可行的、可持续的和可管理的。 (事实上,这就是新语言版本(Christmas
、Diwali
、Eid
(?) 等)的管理方式。)
[3] 我看到有人试图重新祝福使用常规 newclass is oldclass
语法创建的新 class work (on my laptop) and not work (on repl.it) 使用编译器自称是 2019.03.1
。 (据推测 repl.it 安装了一个版本的编译器源代码,或从它编译的二进制文件,在编译器版本更新到 2019.03.1
后不久从主头上获取,并进行了重大更改。我请注意,repl.it 尚未公布他们的在线 raku repl——我是偶然发现的——所以这种情况并没有什么不妥,但它让我更加需要 $RAKU.compiler.verbose-config
在 worked/broken 输出我刚刚 linked.)
it is supposed to work with inherited classes
它从来不应该是那样的将军。我首先设计了 API 并实现了它,它只是作为 mixins 的实现细节。
直到最近,它还不是语言规范测试套件的一部分 - 当它成为其中的一部分时,它已经拥有了当前的、更具限制性的语义。出于性能原因,对它的约束很重要:当我们知道一个类型不是可以作为混合操作目标的类型时,我们可以 JIT 编译对该对象的属性访问更简单(我们支付了额外的条件移动更改之前的每个属性访问,现在只需要在 mixin 目标类型上支付它)。
可以通过使用 MOP 构造 class 来修改原始程序以使其工作。事实上,下面的程序并不完全是原始程序;为了展示如何在 subclass 中提供方法作为匿名角色,我做了一个小调整,以避免过多的 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
虽然这是对原始程序最直接的语义修复,但还有一个更短的方法:在 Person
类型对象上使用 but
运算符来生成混合类型和 return,然后根据自己的喜好调整其名称:
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;
反正就是比原来多了一行。