“compose_attributes”显然是在属性组合之前调用的

jjm*_*elo 6 rakudo metamodel raku

这是做这件事的另一种尝试,本质上是创建一个冻结的类:

my class MetamodelX::Frozen is Metamodel::ClassHOW {

    method compose_attributes(Mu \type) {
        for self.attributes(type, :local ) -> $a {
            my $attr = Attribute.new( :0rw, :0has_accessor, :name( $a.name ),
             :type($a.type), :package($a.package));
            self.add_attribute(type, $attr );
        }
        callsame();
    }
}

my package EXPORTHOW {
    package DECLARE {
        constant frozen = MetamodelX::Frozen;
    }
}
Run Code Online (Sandbox Code Playgroud)

类似于@jnthwrthngtn在这里的答案,其中方法是以特定形状创建的,以防止类如何以通常的方式创建它们,我在这里所做的是以只读方式重新创建属性,并且没有访问器,使用其余强制属性相同。然而,当您尝试实例化它时,这会失败:

Package 'Foo' already has an attribute named '$!bar'
Run Code Online (Sandbox Code Playgroud)

在任何罕见的情况下,这只会消除访问器,因为该属性已经是只读的,并且无法创建真正的冻结类(此外,它仍然可以被增强,因此不会被长期冻结)。您还能想到其他方法来实现同样的目标吗?

Jon*_*ton 8

属性组合并不是向类中添加属性的时候;相反,它是这样的时间:

  • 我们为类提交一组特定的属性,并将其传达给底层运行时(通常是 MoarVM),后者计算对象的内存布局
  • 我们告诉每个Attribute对象自行组合,这是它生成访问器、handles相关方法等的触发器

我不清楚你打算实现什么,因为属性默认情况下是外部只读的,因此如果有人在rw声明的东西上定义一个错误,那么产生错误可能更有意义frozen。如果您确实想修改属性,那么您可能会更幸运地覆盖add_attribute和调整该属性此时的工作方式(例如,类似的东西method add_attribute($obj, $attr) { callwith($obj, $attr.clone(:!rw, :!has_accessor)) }可能会实现您想要的效果)。