自省和 Perl 6 的對(duì)象系統(tǒng)
Perl 6 是構(gòu)建在元對(duì)象層上面的稳诚。那意味著有些對(duì)象(元對(duì)象)控制著各種面向?qū)ο蠼Y(jié)構(gòu)(例如類贱除、roles、方法诀诊、屬性、枚舉,…)怎樣去表現(xiàn)阅嘶。
要感受類的元對(duì)象, 這兒有一個(gè)同樣的例子出現(xiàn)2次: 一次一種 Perl 6中的普通聲明, 一次通過元模型來表達(dá):
class A {
method x() { say 42 }
}
A.x(); # 42
對(duì)應(yīng)于:
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
(除了聲明形式的運(yùn)行在編譯時(shí), 后面這種形式不是)
對(duì)象后面的元對(duì)象能使用 $obj.HOW
獲取, 這兒的 HOW 代表著 Higher Order Workings(或者 HOW the *%@$ does this work?)属瓣。
這兒, 帶有 .^
的調(diào)用是元對(duì)象的調(diào)用, 所以 A.^compose
是 A.HOW.compose(A)
的簡(jiǎn)寫。調(diào)用者也被傳遞到參數(shù)列表中, 以使它能夠支持原型類型風(fēng)格的類型系統(tǒng), 那兒只有一個(gè)元對(duì)象讯柔。
就像上面的例子展示的那樣, 所有的面向?qū)ο筇匦詫?duì)使用者都是可獲得的, 而不僅僅是編譯器抡蛙。實(shí)際上編譯器就是使用元對(duì)象的這樣的調(diào)用的。
元對(duì)象(MetaObjects)
這些是內(nèi)省的宏, 類似于方法調(diào)用魂迄。
元對(duì)象通常以 ALLCAPS(全大寫)命名, 并且避免使用你自己的帶有全大寫名字的方法被認(rèn)為是一個(gè)好的風(fēng)格粗截。這會(huì)避免和可能出現(xiàn)在未來版本中的任何元對(duì)象發(fā)生沖突。注意, 如果你必須使用帶有全大寫名字的方法的話, 把你的這個(gè)方法名字用引號(hào)引起來來間接安全地調(diào)用:
#| 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
類型的類型對(duì)象台妆。例如 42.WHAT
返回 Int
類型對(duì)象。
WHICH
對(duì)象的同一值胳徽。這能用于哈希和同一比較, 并且這是 ===
中綴操作符的實(shí)現(xiàn)方式婿屹。
> "a".WHICH
Str|a
WHO
支持對(duì)象的包
> "a".WHO
Str
WHERE
對(duì)象的內(nèi)存地址灭美。注意這在移動(dòng)的/緊湊的垃圾回收實(shí)現(xiàn)中是不穩(wěn)定的。 在穩(wěn)定的同一指示器中使用 WHERE
昂利。
HOW
元類對(duì)象(the metaclass object):“Higher Order Workings”届腐。
WHY
附加的 Pod 值。
DEFINITE
對(duì)象有一個(gè)有效的強(qiáng)制表現(xiàn)蜂奸。
對(duì)于實(shí)例返回 True
, 對(duì)于類型對(duì)象返回 False
犁苏。
> 42.DEFINITE
True
> Int.DEFINITE
False
VAR
返回底層的 Scalar 對(duì)象, 如果有的話。
元對(duì)象系統(tǒng)的結(jié)構(gòu)
對(duì)于每個(gè)類型聲明符關(guān)鍵字, 例如 class
扩所、role
围详、enum
、module
碌奉、package
短曾、grammar
或subset
, 就有一個(gè)獨(dú)立的元類在 Matamodel::
命名空間中。(Rakudo 在 Perl6::Metamodel::
命名空間中實(shí)現(xiàn)了它們, 然后把 Perl6::Metamodel
映射到 Metamodel
)赐劣。
這些元類(meta classes)中的很多都共享公共的功能。例如 roles哩都、grammars和 classes(類)都能包括方法和屬性, 還能遵守 roles魁兼。這個(gè)共享的功能是在 roles 中實(shí)現(xiàn)的, 它被組合進(jìn)合適的元類中。例如 role Metamodel::RoleContainer實(shí)現(xiàn)了類型能處理 roles 和 Metamodel::ClassHOW
的功能, 它是在 class
關(guān)鍵字后面的元類, 遵守了這個(gè) role漠嵌。
Bootstrapping concerns
你可能想知道為什么 Metamodel::ClassHOW
可以是一個(gè)類, 當(dāng)按照Metamodel::ClassHOW
作為一個(gè)類被定義時(shí), 或者 roles 負(fù)責(zé) role 處理的怎么能是 roles咐汞。答案是通過魔法。
開玩笑啦儒鹿。自舉是特別實(shí)現(xiàn)的化撕。Rakudo 使用語言的對(duì)象系統(tǒng)來實(shí)現(xiàn)自舉, 它恰好(幾乎)就是 Perl 6 的一個(gè)子集: NQP, Not Quite Perl。 NQP 有原始的, class-like 叫做 konwhow
的性質(zhì), 它用于自舉它自己的類和 roles 實(shí)現(xiàn)约炎。konwhow
建立在NQP 提供的虛擬機(jī)的原始基礎(chǔ)上植阴。
因?yàn)樵獙?duì)象是根據(jù)低級(jí)(low-level)類型引導(dǎo)的, 自省有時(shí)能返回低級(jí)(low-level)類型而非你期望的那個(gè)類型, 例如返回一個(gè) NQP-level 的子例程而非普通的 Routine
對(duì)象, 或返回一個(gè)引導(dǎo)的屬性而非Attribute。
組合和靜態(tài)推理
在 Perl 6中, 類型是在解析時(shí)被構(gòu)造的, 所以在開始, 它必須是可變的圾浅。然而, 如果所有類型一直是可變的, 那么關(guān)于類型的所有推斷會(huì)在任何類型的修改時(shí)變得無效掠手。例如父類的列表因此類型檢測(cè)的結(jié)果能在那個(gè)時(shí)候改變。
所以為了獲得這兩個(gè)世界中最好的東西, 當(dāng)類型從可變轉(zhuǎn)為不可變時(shí)是好時(shí)機(jī)狸捕。這就叫做組合, 并且對(duì)于從句法構(gòu)成上聲明的類型, 它發(fā)生在類型聲明被完全解析時(shí)(所以總是在閉合花括號(hào)被解析時(shí))喷鸽。
如果你通過元對(duì)象系統(tǒng)直接創(chuàng)建類型, 你必須要在它們身上調(diào)用 .^compose
, 在它們變得完全起作用之前。
很多元類也使用組合時(shí)來計(jì)算一些諸如方法解析順序這樣的屬性, 發(fā)布一個(gè)方法緩存, 和其它清掃任務(wù)灸拍。在它們被組合之后干預(yù)類型有時(shí)是可能的, 但通常是造成災(zāi)難的因素做祝。 不要那樣做砾省。
能力和責(zé)任
元對(duì)象協(xié)議提供了很多常規(guī) Perl 6 代碼故意限制了的能力, 例如調(diào)用類中不信任你的私有方法, 窺探私有屬性, 和其它通常不能完成的東西。
常規(guī)的 Perl 6 代碼有很多就地的安全檢測(cè); 元模型中不是這樣混槐,它靠近底層的虛擬機(jī), 違反和虛擬機(jī)的約定可以導(dǎo)致所有奇怪的行為, 而在正常代碼中, 顯而易見的會(huì)是 bugs编兄。
所以, 在寫元類型的時(shí)候要格外小心和思考。
能力纵隔、便利和陷阱
元對(duì)象協(xié)議被設(shè)計(jì)的強(qiáng)大到實(shí)現(xiàn) Perl 6 的對(duì)象系統(tǒng)翻诉。這種能力間或花費(fèi)了便利的代價(jià)。
例如, 當(dāng)你寫了 my $x = 42
并在 $x
上調(diào)用方法時(shí), 大部分方法會(huì)在整數(shù) 42 上起作用, 而不是在存儲(chǔ) 42 的標(biāo)量容器上捌刮。這是 Perl 6中設(shè)立的一塊便利碰煌。元對(duì)象協(xié)議中的大部分不能提供自動(dòng)忽略標(biāo)量容器的便利性, 因?yàn)樗鼈円灿糜趯?shí)現(xiàn)那些標(biāo)量容器。 所以, 如果你寫了 my $t = MyType; ... $t.^compose
, 那么你正組合那個(gè)$
變量表明的標(biāo)量, 而不是 MyType
绅作。
結(jié)果就是你需要很詳盡的理解 Perl 6 的底層以避免陷阱, 當(dāng)使用 MOP 時(shí), 并且不能期望得到和普通 Perl 6 代碼提供的 "do what I mean" 的便利芦圾。