Raku rebless不再适用于继承的类


9

该线程中给出的代码不再起作用:如何在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

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

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


可能是回归错误。最好将其报告为Rakudo问题。
jjmerelo

有一些改变去年二月:github.com/perl6/nqp/blob/...
jjmerelo

另外,我已经用脚注指向@jnthn answer docs.raku.org/type/Metamodel::Primitives来更新文档。谢谢,雷夫
jjmerelo

Answers:


11

它应该与继承的类一起使用

从来都不应该这么认为。我设计了该API并首先实现了它,但它只是作为mixin的实现细节而已。

直到最近,它还不是语言规范测试套件的一部分-当它成为语言规范测试套件的一部分时,它已经具有当前的,更具限制性的语义。出于性能原因,对此的约束非常重要:当我们知道某个类型不是可以作为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

虽然这是对原始程序的最直接的语义修复,但是有一种较短的方法:使用类型对象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;

反正这只比原始线多了一行。


constant Woman = Person but role …没有意识到那是可以做到的。因此,对于BEGIN生产线而言,Raku也即将开始做一个JS风格的原型范例!
user0721090601

好。谢谢你的解释。我确实希望它能进入文档,因为docs.raku.org/routine/rebless几乎没有用...我将在不久后更新《 Beginning Raku》。
Arne Sommer

@ user0721090601 Raku支持,引用S12:“基于类和基于原型的OO编程”。但是,如果使用class关键字构造对象,则再次引用S12:“默认情况下,派生自的对象Mu支持相当标准的基于类的模型bless...调用... BUILD例程...默认的BUILD语义是继承自Mu“。总而言之,我认为说Raku支持A) “甚至仅用几行代码就严重扭曲了基于沼泽标准类的OO” B) “基于原型的OO” 更为准确。
雷夫

有关我对重大更改的看法,请参见raku-musings.com/reblessed.html
Arne Sommer

5

请参阅jnthn的答案进行权威性讨论,以了解发生了rebless什么以及如何处理。

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

对于那些对RDD编程语言和相关工件(例如Rakudo编译器和docs.raku.org内容)基础的TDD方法的原理和实践有进一步讨论兴趣的人员,此(超长!)答案可能值得一读。。

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

Arne:此线程中提供的代码不再起作用:如何在Raku中释放一个对象?

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

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

2019年4月的一次承诺中讨论了相关更改,jnthn写道:

最近,rebless开始明确地将作为操作目标的类型创建为mixin目标类型,以帮助优化。...

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

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

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

这个问题在工作原理中也进行了进一步的讨论……突然之间……文档……应该记录下面的调用部分。

Arne:应该用于继承的类。至少是。

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

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

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

Rakudo的行为由可执行的测试套件指定的事实是@Larry确保Raku可靠运行的方法的基本组成部分[1],并且具有深远的意义[2]

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

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

在2019年4月,niner公开了一份关于其影响的rakudo GH问题Inline::Perl5,我在下面摘录了ninr和jnthn之间的交流的一些亮点。

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

niner: TBH我在这里所做的可能总是有点可疑...甚至可能是...我可以摆脱[it] ...虽然保持已经部署的Inline :: Perl5版本正常运行,这还是很好的。

jnthn:以前没有的规格Metamodel::Primitives.rebless。我已经添加了[spectest],所以现在有了。这意味着现在对可以预期起作用的内容以及Inline :: Perl5可以依赖的内容进行了一些定义。

由于未知的命名参数将被忽略,但是:mixin在以前的Rakudo版本中不是必需的,因此有可能制作一个新的Inline :: Perl5版本,该版本可以在以前的Rakudo版本以及即将发布的版本上运行,因此至少可以反向兼容。

我认为没有任何办法可以使现有的Inline :: Perl5版本正常工作...

niner:不幸的是,:mixin在这种情况下传递并没有帮助,因为rebless是在通过创建的子类的子类上完成的Metamodel::Primitives.create_type。子类使用normal Perl6::ClassHOW

我正在努力进行重大重构,以一开始就摆脱繁琐的黑客攻击。我正在重新打开此问题,因此,发行经理知道rakudo的发行候选版本上没有可用的Inline :: Perl5。

jnthn:您是否使用MOP创建该类?如果可以:is_mixin,您可以传递给Perl6::ClassHOW.new_type

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

帮助文档

您在此答案下面的评论中写道:

我可以协助说明文件

对我来说,这听起来像是对您的SOQ核心问题的非常适当且有用的回应。我希望我们有幸实现这一目标。

如果有帮助

同时,您的技术写作非常出色,所以我希望您与其他参与改进工作的最终结果将是一件美妙的事情。

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

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

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

  • 一切都必须假定永远受志愿人员项目的基本性质约束;并且在该约束内:

  • 应当记录烘烤中的 行为,而不应记录其他行为。

(考虑到志愿者的时间,兴趣和共识,有时会记录例外情况,以记录未经烘焙的适当质量检查和批准的Rakudo的行为。在当前实践中,这似乎意味着已发行Rakudo Star中的Rakudo版本的行为。)

无用的文档

该文档没有帮助

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

该文档毫无用处[在2018年]

这是一个非常不同的陈述。

当时没有烧烤入口rebless

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

因此,鉴于人们对docs.raku.org中的内容和不存在的内容达成了共识(请参见上文),因此其rebless页面可以做的最有用的事情是根本不记录文档rebless,或者更好地为其包含一个页面,但是确保它也没有说明它的行为。情况是这样的:该页面确实存在;没有直接的帮助;可以说那总比没有好。

(很容易想象事情会变得更好。例如,如果页面记录功能包括一个百分比,该百分比记录了最新Rakudo Star版本的Rakudo版本中与该功能相关的测试覆盖率状态,0%可以立即提示读者这意味着虽然该文档功能不容易想象,但谁将实现该功能呢?同样容易想象这可能需要历时一年或更长时间才能完成和协作以有效地实施和部署,并且人们认为其他事情更为重要。)

它起作用了...突然没了...文档...应该记录该呼叫

有效

它的运作很“幸运”。

突然不工作了

因为乐堂得到了改善。

文档...应记录呼叫

如前面所述,AIUI当前社会的共识和/或工作的做法是:在文档应该记录的特定版本的号召,即中的最新Rakudo星版本Rakudo的“d行为; 并且可以记录其他版本的行为。

而不是指其他

Aiui,当前的共识和/或工作实践是,一些人可能认为“薄弱”的文档贡献,例如,一些简短的,匆忙撰写的内容和/或文档外部的链接,如果志愿者认为有必要立即进行更改以反映出来,则可以引入用户提出的一些担忧(例如,此SO)以及进行“弱”更改总比什么都不做要好。当然,您可以进行PR来改进它(或者,如果您真的感觉到更改是如此“弱”,会使情况变得更糟,则可以还原它)。

根据我的说法,对2019.11中的更改​​的引用减少了7个月

(根据我的判断,这也是类似的事情,尽管我已经看到一个编译器自称是2019.03.1,并且具有相同的行为中断。[3]

我认为JJ做出了文档更改,他只是误解了jnthn关于如何适应更改的评论。我目前认为这总比没有好,但希望您能对其进行更新。:)

脚注

[1]在拉里(Larry)在2000年的“洋葱状况”演讲中首次宣布导致Raku的项目后的几分钟,他说了以下

问题:[Raku]有规格吗?

拉里:我们特别想强调的...与其说是“语言设计”规范,还不如说是将我们当前的回归测试开发成对语言实际含义的验证测试,并实际探究了所有问题。然后缝隙,说:“这是[Raku],这不是[Raku]”,然后我们实际上有了一个机器可读的规范。对我来说,这实际上比人类可读的单词所说的重要得多。

[2]当然,只有在给定的用户的测试足以满足其需求的情况下,烘烤才可以很好地发挥作用。阿尔恩(Arne)的问题表明,覆盖范围的漏洞如何令人惊讶。有关这些漏洞在2018年的讨论,请参阅“规范,版本控制,更改和……破损”。好消息是,烘烤只是用Raku编写的大量单元测试,用于测试具有特定值的表达式或构造是否具有特定功能。因此,个人或公司很容易贡献新的测试以提高测试覆盖率。而且它们都在版本控制(git)下,因此自定义的下游标签,分支和fork是可行,可持续和可管理的。(事实上,这就是如何将新语言版本(ChristmasDiwaliEid(?)等)进行管理。)

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


当我试图弄清楚“毫不费力”的工作原理时,我发现了这篇文章,因为该文档没有用: stackoverflow.com/questions/44486985/… 然后它起作用了。然后突然不起作用了,文档仍然没用。它仍然是,因为它应该记录调用,而不引用其他内容。根据我的说法,对2019.11中的更改​​的引用减少了7个月。
阿恩·索默

如果有帮助,我可以为文档提供帮助。
阿恩·索默

@ArneSommer请参阅我的答案中的新部分,以帮助文档开始
雷夫

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.