如何使用元对象协议向对象添加属性?

How to add an attribute to an object using the meta-object protocol?

我试图回答 问题,并认为我可以使用元对象协议将属性添加到 class。这是一个最小的例子,我尝试在构造后将属性 test 添加到 class Configuration

use v6;

class Configuration {
}

my $config = Configuration.new;
my $attr = Attribute.new(
    :name('$.test'), # Trying to add a "test" attribute
    :type(Str),
    :has_accessor(1), 
    :package(Configuration)
);
$config.^add_attribute( $attr );
$config.^compose();
say "Current attributes: ", join ', ', $config.^attributes();
$attr.set_value( $config, "Hello" ); # <-- This fails with no such attribute '$.test'
say $config.test;

当我 运行 这个时,我得到:

Current attributes: $.test
P6opaque: no such attribute '$.test' on type Configuration in a Configuration when trying to bind a value
  in block <unit> at ./p.p6 line 16

组合时class后不能添加属性,发生在编译程序时到达收尾}时的编译时。 (P6opaque 表示就是这种情况。存在允许这样做的表示并非不可能,但此时指定了 none。)

此外,在元对象上调用 .^add_attribute,对于 class,属性是按类型而不是按对象;代码结构表明,也许期望是针对每个对象的。没有任何东西使得原型对象定向成为不可能(实际上 MOP 的设计是为了让某人可以在 Perl 6 中实现这样的对象系统),但是 Perl 6 本身也没有指定任何东西来提供这个。

因此,对于提供的对象系统,此类操作需要在编译时和关闭之前完成 }。可以通过以下方式实现:

class Configuration {
    BEGIN {
        my $attr = Attribute.new(
            :name('$!test'), # Trying to add a "test" attribute
            :type(Str),
            :has_accessor(1),
            :package(Configuration)
        );
        Configuration.^add_attribute( $attr );
    }
}

my $config = Configuration.new;
say "Current attributes: ", join ', ', $config.^attributes();
$config.^attributes[0].set_value( $config, "Hello" );
say $config.test;

这是 Perl 6 动态的众多地方之一,主要是邀请程序员参与编译时,而不是在运行时使所有事情成为可能。

最后,我会注意到有一种方法可以为现有对象添加属性,并且是在每个对象的基础上:通过使用 does 将角色混合到其中。这是通过沿途更改对象的类型来实现的。 does here.

上有一些文档