Raku rebless 不再适用于继承类

2023-11-26

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


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

它从来不应该是那么普遍。我首先设计并实现了该 API,它只是作为 mixins 的实现细节。

直到最近,它还不是语言规范测试套件的一部分 - 当它成为语言规范测试套件的一部分时,它已经拥有了当前的、更具限制性的语义。出于性能原因,对其的约束很重要:当我们知道某种类型不能成为 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输入 object 来生成 mixin 类型并返回它,然后根据您的喜好调整其名称:

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;

无论如何,这只比原来多了一行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Raku rebless 不再适用于继承类 的相关文章

随机推荐