2.Dynamicdispatch(按照對象運行時真正類型來決定)
(按,熟悉C++的朋友們一定微笑了,這再簡單不過了。)
staticdispatch沒什麼可說的。
dynamicdispatch卻有一個有趣的屬性。那就是,subsumption一定不能影響對象的狀態。如果在subsumption的時候,改變了這個對象的狀態,比如象C++中的對象切片,那麼動態解析的方法就可能會失敗。
好在,這個屬性無論對語義,還是對效率,都是很有好處的。
(按,C++中的objectslicing會把新的對象的vptr初始化成它自己類型的vtable指針,所以不存在動態解析的問題。但實際上,對象切片根本不能叫做subsumption。
具體語言實現中,如C++,雖然subsumption不會改變對象內部的狀態,但指針的值卻是可能會變化的。這也是一個讓人討厭的東西,但C++vtable的方案卻隻能這樣。有一種變種的vtable方法,可以避免指針的變化,也更高效。會在另外的文章中闡述這種方法。)
關於類型信息
雖然subsumption並不改變對象的狀態,在一些語言裡(如Java),它甚至沒有任何運行時開銷。但是,它卻使丟掉了一些靜態的類型信息。
比如說,有一個類型InstanceTypeOf(Object),而Object類裡沒有定義任何屬性和方法。又有一個類MyObject,它繼承自Object。那麼當把MyObject的對象當作InstanceTypeOf(Object)類型來處理的時候,就得到了一個什麼東西也沒有的沒用的空對象。
當然,如果考慮一個不那麼極端的情況,比如說,Object類裡麵定義了一個方法f,而MyObject對方法f做了重載,那麼,通過dynamicdispatch,還是可以間接地操作MyObject中的屬性和方法的。這也是麵向對象設計和編程的典型方法。
從一個purist的角度看,dynamicdispatch是唯一應該用來操作已經被subsumption忘掉的屬性和方法的東西。它優雅,安全,所有的榮耀都歸於dynamicdispatch!!!
不過,讓purist們失望的是,大部分語言還是提供了一些在運行時檢查對象類型,並從而操作被subsumption遺忘的屬性和方法。這種方法一般被叫做RTTI(RunTimeTypeIdentification)。如C++中的dynamic_cast,或Java中的instanceof.
實事求是地說,RTTI是有用的。但因為一些理論上以及方法論上的原因,它被認為是破壞了麵向對象的純潔性。
首先,它破壞了抽象,使一些本來不應該被使用的方法和屬性被不正確地使用。
其次,因為運行時類型的不確定性,它有效地把程序變得更脆弱。
第三點,也許是最重要的一點,它使程序缺乏擴展性。當加入了一個新的類型時,也許需要仔細閱讀dynamic_cast或instanceof的代碼,必要時改動它們,以保證這個新的類型的加入不會導致問題。
很多人一提到RTTI,總是側重於它的運行時的開銷。但是,相比於方法論上的缺點,這點運行時的開銷真是無足輕重的。
而在purist的框架中(按,吸一口氣,目視遠方,做深沉狀),新的子類的加入並不需要改動已有的代碼。
這是一個非常好的優點,尤其是當並不擁有全部源代碼時。
總的來說,雖然RTTI(也叫typecase)似乎是不可避免的一種特性,但因為它的方法論上的一些缺點,它必須被非常謹慎的使用。今天麵向對象語言的類型係統中的很多東西就是產生於避免RTTI的各種努力。
比如有些複雜的類型係統中可以在參數和返回值上使用Self類型來避免RTTI.這點後麵會介紹到。
協變,反協變和壓根兒不變
協變,反協變和壓根兒不變(Covarance,ContravarianceandInvariance)
在下麵的幾個小節裡,來介紹一種避免RTTI的類型技術。在此之前,先來介紹“協變”,“反協變”和“壓根兒不變”的概念。
協變
首先,來看一個Pair類型:A*B
這個類型支持一個getA()的操作以返回這個Pair中的A元素。
給定一個A’<:A,那麼,可以說A’*B<:A*B。
為什麼呢?可以用Subsumption的屬性加以證明:
假設有一個A’*B類型的對象a’*b,這裡,a’:A’,b:B,a’*b<:A’*B
那麼,因為,A’<:A,從subsumption,可以知道a’:A,getA():A所以,a’*b<:A*B
這樣,就定義A*B這個類型對於A是協變的。
w t . p o o在盡節章說小新最
。的變協是也B於對B*A明證以可也,理同
:的義定樣這是ecnairavoC,說點一規正
,麼那。的成合組T型類過通是L型類,裡這,)T(L定給
。的變協T對是L說就麼那,)2T(L:<)1T(L出推夠能2T:<1T果如
變協反
)A>-B:f即,潔簡更許也義定的egaugnallanoitcnuf用(;)bB(fA:數函個一看請
?呢係關epytbus的樣麼什有間之A>-’B和A’B個一定給,麼那
。AA>-B,明證以可
。導推做再不,幅篇於基
。的變協反是型類數參的數函,以所
:的樣這是義定的點規正的ecnairavartnoC
,麼那。的成合組T型類過通是L型類,裡這,)T(L定給
。的變協反T對是L說就麼那,)1T(L:<)2T(L出推夠能2T:<1T果如
。的變協是型類回返的數函,明證以可,樣同
兒根壓