Perl 6 中的元对象协议

自省和 Perl 6 的对象系统


Perl 6 是构建在元对象层上面的。那意味着有些对象(元对象)控制着各种面向对象结构(例如类、roles、方法、属性、枚举,…)怎样去表现。

要感受类的元对象, 这儿有一个同样的例子出现2次: 一次一种 Perl 6中的普通声明, 一次通过元模型来表达:

class A {
    method x() { say 42 }
}
A.x(); # 42

对应于:

constant A := Metamodel::ClassHOW.new_type( name => 'A' );  # class A {
A.^add_method('x', my method x(A:) { say 42 });             # method x() .. .
A.^compose;                                                 # }

A.x(); # 42

(除了声明形式的运行在编译时, 后面这种形式不是)

对象后面的元对象能使用 $obj.HOW获取, 这儿的 HOW 代表着 Higher Order Workings(或者 HOW the *%@$ does this work?)。

这儿, 带有 .^的调用是元对象的调用, 所以 A.^composeA.HOW.compose(A)的简写。调用者也被传递到参数列表中, 以使它能够支持原型类型风格的类型系统, 那儿只有一个元对象。

就像上面的例子展示的那样, 所有的面向对象特性对使用者都是可获得的, 而不仅仅是编译器。实际上编译器就是使用元对象的这样的调用的。

元对象(MetaObjects)


这些是内省的宏, 类似于方法调用。

元对象通常以 ALLCAPS(全大写)命名, 并且避免使用你自己的带有全大写名字的方法被认为是一个好的风格。这会避免和可能出现在未来版本中的任何元对象发生冲突。注意, 如果你必须使用带有全大写名字的方法的话, 把你的这个方法名字用引号引起来来间接安全地调用:

#| THIS IS A CLASS FOR SHOUTING THINGS
class MY-CLASSES-ARE-ALL-CAPS {
    method WHY { "I DON'T KNOW" }
}
my $c = MY-CLASSES-ARE-ALL-CAPS.new;
say $c.WHY      # "THIS IS A CLASS FOR SHOUTING THINGS"? 显示这?你在逗我!
say $c."WHY"()  # "I DON'T KNOW"

WHAT


类型的类型对象。例如 42.WHAT 返回 Int类型对象。

WHICH


对象的同一值。这能用于哈希和同一比较, 并且这是 ===中缀操作符的实现方式。

> "a".WHICH
Str|a

WHO


支持对象的包

> "a".WHO
Str

WHERE


对象的内存地址。注意这在移动的/紧凑的垃圾回收实现中是不稳定的。 在稳定的同一指示器中使用 WHERE

HOW


元类对象(the metaclass object):“Higher Order Workings”。

WHY


附加的 Pod 值。

DEFINITE


对象有一个有效的强制表现。

对于实例返回 True, 对于类型对象返回 False

> 42.DEFINITE
True
> Int.DEFINITE
False

VAR


返回底层的 Scalar 对象, 如果有的话。

元对象系统的结构


对于每个类型声明符关键字, 例如 classroleenummodulepackagegrammarsubset, 就有一个独立的元类在 Matamodel::命名空间中。(Rakudo 在 Perl6::Metamodel::命名空间中实现了它们, 然后把 Perl6::Metamodel映射到 Metamodel)。

这些元类(meta classes)中的很多都共享公共的功能。例如 roles、grammars和 classes(类)都能包括方法和属性, 还能遵守 roles。这个共享的功能是在 roles 中实现的, 它被组合进合适的元类中。例如 role Metamodel::RoleContainer实现了类型能处理 roles 和 Metamodel::ClassHOW的功能, 它是在 class关键字后面的元类, 遵守了这个 role。

Bootstrapping concerns


你可能想知道为什么 Metamodel::ClassHOW可以是一个类, 当按照Metamodel::ClassHOW作为一个类被定义时, 或者 roles 负责 role 处理的怎么能是 roles。答案是通过魔法。

开玩笑啦。自举是特别实现的。Rakudo 使用语言的对象系统来实现自举, 它恰好(几乎)就是 Perl 6 的一个子集: NQP, Not Quite Perl。 NQP 有原始的, class-like 叫做 konwhow 的性质, 它用于自举它自己的类和 roles 实现。konwhow建立在NQP 提供的虚拟机的原始基础上。

因为元对象是根据低级(low-level)类型引导的, 自省有时能返回低级(low-level)类型而非你期望的那个类型, 例如返回一个 NQP-level 的子例程而非普通的 Routine对象, 或返回一个引导的属性而非Attribute

组合和静态推理


在 Perl 6中, 类型是在解析时被构造的, 所以在开始, 它必须是可变的。然而, 如果所有类型一直是可变的, 那么关于类型的所有推断会在任何类型的修改时变得无效。例如父类的列表因此类型检测的结果能在那个时候改变。

所以为了获得这两个世界中最好的东西, 当类型从可变转为不可变时是好时机。这就叫做组合, 并且对于从句法构成上声明的类型, 它发生在类型声明被完全解析时(所以总是在闭合花括号被解析时)。

如果你通过元对象系统直接创建类型, 你必须要在它们身上调用 .^compose, 在它们变得完全起作用之前。

很多元类也使用组合时来计算一些诸如方法解析顺序这样的属性, 发布一个方法缓存, 和其它清扫任务。在它们被组合之后干预类型有时是可能的, 但通常是造成灾难的因素。 不要那样做。

能力和责任


元对象协议提供了很多常规 Perl 6 代码故意限制了的能力, 例如调用类中不信任你的私有方法, 窥探私有属性, 和其它通常不能完成的东西。

常规的 Perl 6 代码有很多就地的安全检测; 元模型中不是这样,它靠近底层的虚拟机, 违反和虚拟机的约定可以导致所有奇怪的行为, 而在正常代码中, 显而易见的会是 bugs。

所以, 在写元类型的时候要格外小心和思考。

能力、便利和陷阱


元对象协议被设计的强大到实现 Perl 6 的对象系统。这种能力间或花费了便利的代价。

例如, 当你写了 my $x = 42并在 $x上调用方法时, 大部分方法会在整数 42 上起作用, 而不是在存储 42 的标量容器上。这是 Perl 6中设立的一块便利。元对象协议中的大部分不能提供自动忽略标量容器的便利性, 因为它们也用于实现那些标量容器。 所以, 如果你写了 my $t = MyType; ... $t.^compose, 那么你正组合那个$变量表明的标量, 而不是 MyType

结果就是你需要很详尽的理解 Perl 6 的底层以避免陷阱, 当使用 MOP 时, 并且不能期望得到和普通 Perl 6 代码提供的 "do what I mean" 的便利。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容