Ruby Class Mechanism
今天凌晨終於看到 Ruby class 機制細節。
在 Ruby,萬事萬物皆物件,所以 class 亦為物件,記憶體佈局就是條「object → class (object) → superclass (object) → … → Object
」的單向鏈結串列(singly-linked list)。這條 singly-linked list 所用的指標,實作上稱為 klass
,當喚起一個 object(incl. class object)的函式,便從「這個 object 的 klass
pointer」所指的 class object 開始搜尋,找到就喚起,未找到則上溯繼承鏈(at runtime),如此遞迴實施。如果整條串鏈都不含此函式,便喚起 Object#method_missing
。
Ruby 更可以插入 singleton methods 而產生所謂 singleton class(和 Singleton pattern 無關),即「為某一個 object 量身打造一個 class」。而既然 class 也是 object,於是就可以透過 singleton class 機制,造出 class instance variables / methods(但並非 class variables / methods)。而想喚起 class object 的 instance methods,為了一致,必須從它的 klass
pointer 所指的 class object 開始搜尋,於是有了 metaclass,但這個 metaclass 和 Smalltalk 用以生成多個 class 的 metaclass 不同,只是為了一致而存在的 singleton class,在語言層面無法接觸 metaclass objects。
至於 Ruby 用來補償多繼承(multiple inheritance)的 mixin 功能,就只是把 mixin 插入那條(單)繼承鏈內。
這種設計當然相當彈性。Ruby 支援在任意時刻再次打開 class definition 加以塗改,而所有這個 class 的 objects 都會受影響,從上述機制很清楚能看到這點 ─ indirection 帶來的彈性。然而,喚起一個函式的 time complexity 是 O(C + M)
,其中 C
是繼承鏈的深度,M
是繼承鏈中所用的 mixins 個數,效能負擔很重(C++ virtual functions 只多了 vptr
/ vtbl
的間接性,就在效率上被人抨擊)。PickAxe(即《Programming Ruby, 2/e》之暱稱)在 Part III 最後說:
The important thing to remember about Ruby is that there isn't a big difference between "compile time" and "run time." It's all the same. You can add code to a running process. You can redefine methods on the fly, change their scope from
public
toprivate
, and so on. You can even alter basic types, such asClass
andObject
.Once you get used to this flexibility, it is hard to go back to a static language such as C++ or even to a half-static language such as Java.
But then, why would you want to do that?
"For efficiency, of course," I said. 說「compile time 和 run time 全然相同」,其實是省略了 compile time,把工作全移到 run time。這的確增加不少彈性,但也損失不少效率。"Efficiency (compile time) vs. flexibility (run time)",很經典的 trade-off 問題。
<< 回到主頁