1995年3月,dr.dobb‘s journal特約記者, 著名技術(shù)書籍作家al stevens采訪了stl創(chuàng)始人alexander
stepanov. 這份訪談紀錄是迄今為止對于stl發(fā)展歷史的最完備介紹, 侯捷先生在他的stl有關(guān)文章里推薦大家閱讀這篇文章.
因此我將該文全文翻譯如下:
q: 您對于generic programming進行了長時間的研究, 請就此談談.
a: 我開始考慮有關(guān)gp的問題是在70年代末期, 當時我注意到有些算法并不依賴于數(shù)據(jù)結(jié)構(gòu)的特定實現(xiàn),而只是依賴于該結(jié)構(gòu)的幾個基本的語義屬性.
于是我開始研究大量不同的算法,結(jié)果發(fā)現(xiàn)大部分算法可以用這種方法從特定實現(xiàn)中抽象出來, 而且效率無損. 對我來說,效率是至關(guān)重要的,
要是一種算法抽象在實例化會導致性能的下降, 那可不夠棒.
當時我認為這項研究的正確方向是創(chuàng)造一種編程語言. 我和我的兩個朋友一起開始干起來.一個是現(xiàn)在的紐約州立大學教授deepak
kapur, 另一個是倫塞里爾技術(shù)學院教授david musser.當時我們?nèi)齻€在通用電器公司研究中心工作.
我們開始設(shè)計一種叫tecton的語言. 該語言有一種我們稱為"通用結(jié)構(gòu)"的東西, 其實不過是一些形式類型和屬性的集合體,
人們可以用它來描述算法. 例如一些數(shù)學方面的結(jié)構(gòu)充許人們在其上定義一個代數(shù)操作, 精化之,擴充之, 做各種各樣的事.
雖然有很多有趣的創(chuàng)意, 最終該項研究沒有取得任何實用成果, 因為tecton語言是函數(shù)型語言.
我們信奉backus的理念,相信自己能把編程從von neumann風格中解放出來. 我們不想使用副效應, 這一點限制了我們的能力,
因為存在大量需要使用諸如"狀態(tài)", "副效應"等觀念的算法.
我在70年代末期在tecton上面所認識到了一個有趣的問題: 被廣泛接受的adt觀念有著根本性的缺陷.
人們通常認為adt的特點是只暴露對象行為特征, 而將實現(xiàn)隱藏起來. 一項操作的復雜度被認為是與實現(xiàn)相關(guān)的屬性, 所以抽象的時候應予忽略.
我則認識到, 在考慮一個(抽象)操作時, 復雜度(或者至少是一般觀念上的復雜度)必須被同時考慮在內(nèi). 這一點現(xiàn)在已經(jīng)成了gp的核心理念之一.
例如一個抽象的棧stack類型, 僅僅保證你push進去的東西可以隨后被pop出來是不夠的,同樣極端重要的是,
不管stack有多大, 你的push操作必須能在常數(shù)時間內(nèi)完成. 如果我寫了一個stack, 每push一次就慢一點, 那誰都不會用這個爛玩藝.
我們是要把實現(xiàn)和界面分開, 但不能完全忽略復雜度. 復雜度必須是, 而且也確實是橫陳于模塊的使用者與實現(xiàn)者之間的不成文契約.
adt觀念的引入是為了允許軟件模塊相互可替換. 但除非另一個模塊的操作復雜度與這個模塊類似,
否則你肯定不愿意實現(xiàn)這種互換.如果我用另外一個模塊替換原來的模塊, 并提供完全相同的接口和行為, 但就是復雜度不同, 那么用戶肯定不高興.
就算我費盡口舌介紹那些抽象實現(xiàn)的優(yōu)點, 他肯定還是不樂意用. 復雜度必須被認為是接口的一部分.
1983年左右, 我轉(zhuǎn)往紐約布魯克林技術(shù)大學任教. 開始研究的是圖的算法, 主要的合作伙伴是現(xiàn)在ibm的aaron
kershenbaum. 他在圖和網(wǎng)絡(luò)算法方面是個專家, 我使他相信高序(high order)的思想和gp能夠應用在圖的算法中.
他支持我與他合作開始把這些想法用于實際的網(wǎng)絡(luò)算法. 某些圖的算法太復雜了, 只進行過理論分析, 從來沒有實現(xiàn)過.
他企圖建立一個包含有高序的通用組件的工具箱, 這樣某些算法就可以實現(xiàn)了.
我決定使用lisp語言的一個變種scheme語言來建立這樣一個工具箱. 我們倆建立了一個巨大的庫, 展示了各種編程技術(shù).網(wǎng)絡(luò)算法是首要目標.
不久當時還在通用電器的david musser加了進來, 開發(fā)了更多的組件,一個非常大的庫. 這個庫供大學里的本科生使用, 但從未商業(yè)化.
在這項工作中, 我了解到副效應是很重要的, 不利用副效應, 你根本沒法進行圖操作. 你不能每次修改一個端點(vertex)時都在圖上兜圈子.
所以, 當時得到的經(jīng)驗是在實現(xiàn)通用算法時可以把高序技術(shù)和副效應結(jié)合起來. 副效應不總是壞的, 只有在被錯誤使用時才是.
1985年夏, 我回到通用電器講授有關(guān)高序程序設(shè)計的課程. 我展示了在構(gòu)件復雜算法時這項技術(shù)的應用. 有一個聽課的人叫陳邇,
當時是信息系統(tǒng)實驗室的主任. 他問我是否能用ada語言實現(xiàn)這些技術(shù), 形成一個工業(yè)強度的庫, 并表示可以提供支持. 我是個窮助教,
所以盡管我當時對于ada一無所知, 我還是回答"好的". 我跟dave musser一起建立這個ada庫. 這是很重要的一個時期,
從象scheme那樣的動態(tài)類型語言(dynamically typed language)轉(zhuǎn)向ada這樣的強類型語言,
使我認識到了強類型的重要性. 誰都知道強類型有助于糾錯. 我則發(fā)現(xiàn)在ada的通用編程中, 強類型是獲取設(shè)計思想的有力工具. 它不僅是查錯工具,
而且是思想工具.這項工作給了我對于組件空間進行正交分解的觀念. 我認識到, 軟件組件各自屬于不同的類別.oop的狂熱支持者認為一切都是對象.
但我在ada通用庫的工作中認識到, 這是不對的. 二分查找就不是個對象, 它是個算法. 此外, 我還認識到,
通過將組件空間分解到幾個不同的方向上, 我們可以減少組件的數(shù)量, 更重要的是, 我們可以提供一個設(shè)計產(chǎn)品的概念框架.
隨后, 我在貝爾實驗室c++組中得到一份工作, 專事庫研究. 他們問我能不能用c++做類似的事.我那時還不懂c++, 但當然,
我說我行. 可結(jié)果我不行, 因為1987年時, c++中還沒有模板, 這玩意兒在通用編程中是個必需品. 結(jié)果只好用繼承來獲取通用性,
那顯然不理想.直到現(xiàn)在c++繼承機制也不大用在通用編程中, 我們來說說為什么. 很多人想用繼承實現(xiàn)數(shù)據(jù)結(jié)構(gòu)和容器類, 結(jié)果幾乎全部一敗涂地.
c++的繼承機制及與之相關(guān)的編程風格有著戲劇性的局限. 用這種方式進行通用編程, 連等于判斷這類的小問題都解決不了. 如果你以x類作為基類,
設(shè)計了一個虛函數(shù)operater==, 接受一個x類對象, 并由x派生類y, 那么y的operator==是在拿y類對象與x類對象做比較.
以動物為例, 定義animal類, 派生giraffe(長頸鹿)類. 定義一個成員函數(shù)mate(), 實現(xiàn)與另一個哺乳動物的交配操作,
返回一個animal對象. 現(xiàn)在看看你的派生類giraffe,它當然也有一個mate()方法, 結(jié)果一個長頸鹿同一個動物交配,
返回一個動物對象. 這成何體統(tǒng)?當然, 對于c++程序員來說, 交配函數(shù)沒那么重要, 可是operator==就很重要了.
對付這種問題, 你得使用模板. 用模板機制, 一切如愿.
盡管沒有模板, 我還是搞出來一個巨大的算法庫, 后來成了unix system laboratory standard
component library的一部分. 在bell lab, 我從象andy koenig, bjarne
stroustrup(andrew koenig, 前iso c++標準化委員會主席; bjarne stroustrup, c++之父 --
譯者)這類專家身上學到很多東西. 我認識到c/c++的重要, 它們的一些成功之處是不能被忽略的. 特別是我發(fā)現(xiàn)指針是個好東東.
我不是說空懸的指針, 或是指向棧的指針. 我是說指針這個一般觀念. 地址的觀念被廣泛使用著. 沒有指針我們就沒法描述并行算法.
我們現(xiàn)在來探討一下為什么說c是一種偉大的語言. 通常人們認為c是編程利器并且獲得如此成功,是因為unix是用c寫的. 我不同意.
計算機的體系結(jié)構(gòu)是長時間發(fā)展演變的結(jié)果, 不是哪一個聰明的人創(chuàng)造的.
事實上是廣大程序員在解決實際問題的過程中提出的要求推動了那些天才提出這些體系. 計算機經(jīng)過多次進化, 現(xiàn)在只需要處理字節(jié)地址索引的內(nèi)存,
線性地址空間和指針. 這個進化結(jié)果是對于人們要求解決問題的自然反映. dennis ritchie天才的作品c,
正反映了演化了30年的計算機的最小模型. c當時并不是什么利器. 但是當計算機被用來處理各種問題時, 作為最小模型的c成了一種非常強大的語言,
在各個領(lǐng)域解決各種問題時都非常高效. 這就是c可移植性的奧秘, c是所有計算機的最佳抽象模型, 而且這種抽象確確實實是建立在實際的計算機,
而不是假想的計算機上的. 人們可以比較容易的理解c背后的機器模型, 比理解ada和scheme語言背后的機器模型要容易的多.
c的成功是因為c做了正確的事, 不是因為at&t的極力鼓吹和unix.
c++的成功是因為bjarne stroustrup以c為出發(fā)點來改進c, 引入更多的編程技術(shù),
但始終保持在c所定義的機器模型框架之內(nèi), 而不是閉門造車地自己搞出一個新的機器模型來. c的機器模型非常簡單. 你擁有內(nèi)存,
對象保存在那里面, 你又有指向連續(xù)內(nèi)存空間的指針, 很好理解. c++保留了這個模型, 不過大大擴展了內(nèi)存中對象的范疇,
畢竟c的數(shù)據(jù)類型太有限了, 它允許你建立新的類型結(jié)構(gòu), 但不允許你定義類型方法. 這限制了類型系統(tǒng)的能力.
c++把c的機器模型擴展為真正類型系統(tǒng).
1988年我到惠普實驗室從事通用庫開發(fā)工作. 但實際上好幾年我都是在作磁盤驅(qū)動器. 很有趣但跟
gp毫不相關(guān). 92年我終于回到了gp領(lǐng)域, 實驗室主任bill worley建立了一個算法研究項目, 由我
負責. 那時候c++已經(jīng)有模板了. 我發(fā)現(xiàn)bjarne的模板設(shè)計方案是非常天才的. 在bell lab時, 我參
加過有關(guān)模班設(shè)計的幾個早期的討論, 跟bjarne吵得很兇, 我認為c++的模板設(shè)計應該盡可能向ada的
通用方案看齊. 我想可能我吵得太兇了, 結(jié)果bjarne決定堅決拒絕我的建議. 我當時就認識到在c++
中設(shè)置模板函數(shù)的必要性了, 那時候好多人都覺得最好只有模板類. 不過我覺得一個模板函數(shù)在使用
之前必須先顯式實例化, 跟ada似的. bjarne死活不聽我的, 他把模板函數(shù)設(shè)計成可以用重載機制來
隱式實例化. 后來這個特別的技術(shù)在我的工作中變得至關(guān)重要, 我發(fā)現(xiàn)它容許我做很多在ada中不可能
的任務. 非常高興bjarne當初沒聽我的.
q: 您是什么時候第一次構(gòu)思stl的, 最初的目的是什么?
a: 92年那個項目建立時由8個人, 漸漸地人越來越少, 最后剩下倆, 我和李夢, 而且李小姐是這個領(lǐng)域的新手.
在她的專業(yè)研究中編譯器是主要工作, 不過她接受了gp研究的想法, 并且堅信此項研究將帶給軟件開發(fā)一個大變化,
要知道那時候有這個信念的認可是寥寥無幾. 沒有她, 我可不敢想象我能搞定stl, 畢竟stl標著兩個人的名字:stepanov和lee.
我們寫了一個龐大的庫, 龐大的代碼量, 龐大的數(shù)據(jù)結(jié)構(gòu)組件,函數(shù)對象, 適配器類, 等等. 可是雖然有很多代碼, 卻沒有文檔.
我們的工作被認為是一個驗證性項目,其目的是搞清楚到底能不能在使算法盡可能通用化的前提下仍然具有很高的效率. 我們化了很多時間來比較,
結(jié)果發(fā)現(xiàn), 我們算法不僅最通用, 而且要率與手寫代碼一樣高效, 這種程序設(shè)計風格在性能上是不打折扣的! 這個庫在不斷成長,
但是很難說它是什么時候成為一個"項目"的. stl的誕生是好幾件事情的機緣巧合才促成的.
q: 什么時候, 什么原因促使您決定建議使stl成為ansi/iso標準c++一部分的?
a: 1993年夏, andy koenig跑到斯坦福來講c++課, 我把一些有關(guān)的材料給他看,
我想他當時確實是很興奮.他安排我9月到圣何塞給c++標準委員會做一個演講. 我演講的題目是"c++程序設(shè)計的科學", 講得很理論化,
要點是存在一些c++的基本元素所必須遵循的, 有關(guān)基本操作的原則. 我舉了一些例子, 比如構(gòu)造函數(shù), 賦值操作, 相等操作.
作為一種語言, c++沒有什么限制. 你可以用operator==()來做乘法. 但是相等操作就應該是相等操作. 它要有自反性, a
== a; 它要有對稱性, a == b 則 b == a; 它還要有傳遞性. 作為一個數(shù)學公理, 相等操作對于其他操作是基本的要素.
構(gòu)造函數(shù)和相等操作之間的聯(lián)系就有公理性的東西在里邊. 你用拷貝構(gòu)造函數(shù)生成了一個新對象, 那么這個對象和原來那個就應該是相等的.
c++是沒有做強行要求, 但是這是我們都必須遵守這個規(guī)則. 同樣的, 賦值操作也必須產(chǎn)生相等的對象. 我展示了一些基本操作的"公理",
還講了一點迭代子(iterator), 以及一些通用算法怎樣利用迭代子來工作. 我覺得那是一個兩小時的枯燥演講, 但卻非常受歡迎.
不過我那時并沒有想把這個東西塞在標準里, 它畢竟是太過先進的編程技術(shù), 大概還不適于出現(xiàn)在現(xiàn)實世界里, 恐怕那些做實際工作的人對它沒什么興趣.
我是在9月做這個演講的, 直到次年(1994)月, 我都沒往ansi標準上動過什么腦筋. 1月6日, 我收到andy
koenig的一封信(他那時是標準文檔項目編輯), 信中說如果我希望stl成為標準庫的一部分, 可以在1月25日之前提交一份建議到委員會.
我的答復是:"andy, 你發(fā)瘋了嗎?", 他答復道:"不錯, 是的我發(fā)瘋了, 為什么咱們不瘋一次試試看?"
當時我們有很多代碼, 但是沒有文檔, 更沒有正式的建議書. 李小姐和我每星期工作80小時, 終于在期限之前寫出一份正式的建議書.
當是時也, 只有andy一個人知道可能會發(fā)生些什么. 他是唯一的支持者, 在那段日子里他確實提供了很多幫助. 我們把建議寄出去了,
然后就是等待. 在寫建議的過程中我們做了很多事. 當你把一個東西寫下來, 特別是想到你寫的可能會成為標準, 你就會發(fā)現(xiàn)設(shè)計中的所有紕漏.
寄出標準后,我們不得不一段一段重寫了庫中間的代碼, 以及幾百個組件, 一直到3月份圣迭戈會議之前. 然后我們又重新修訂了建議書,
因為在重新寫代碼的過程中, 我們又發(fā)現(xiàn)建議書中間的很多瑕疵.
q: 您能描述一下當時委員會里的爭論嗎? 建議一開始是被支持呢, 還是反對?
a: 我當時無法預料會發(fā)生些什么. 我做了一個報告, 反響很好. 但當時有許多反對意見. 主要的意見是:這是一份龐大的建議, 而且來得太晚,
前一次會議上已經(jīng)做出決議, 不在接受任何大的建議. 而這個東西是有史以來最大的建議, 包括了一大堆新玩藝. 投票的結(jié)果很有趣,
壓倒多數(shù)的意見認為應對建議進行再考慮, 并把投票推遲到下次會議, 就是后來眾所周知的滑鐵盧會議.
bjarne stroustrup成了stl的強有力支持者.
很多人都通過建議、更改和修訂的方式給予了幫助。bjarne干脆跑到這來跟我們一起工作了一個禮拜。andy更是無時無刻的幫助我們。c++是一種復雜
的語言,不是總能搞得清楚確切的含義的。差不多每天我都要問andy和bjarne c++能不能干這干那。我得把特殊的榮譽歸于andy,
是他提出把stl作為c++標準庫的一部分;而bjarne也成了委員會中stl的主要鼓吹者。其他要感謝的人還有:mike
vilot,標準庫小組的負責人; rogue wave公司的nathan myers(rogue wave是boland
c++builder中stl方案的提供商 —— 譯者),andersen咨詢公司的larry podmolik。確實有好多人要致謝。
在圣迭戈提出的stl實際與當時的c++,我們被要求用新的ansi/iso c++語言特性重寫stl,這些特性中有一些是尚未實現(xiàn)的。為了正確使用這些新的、未實現(xiàn)的c++特性,bjarne和andy花了無以計數(shù)的時間來幫助我們。
人們希望容器獨立于內(nèi)存模式,這有點過分,因為語言本身并沒有包括內(nèi)存模式。所以我們得要想出一些機制來抽象內(nèi)存模式。在stl的早期版本里,假定容器的
容積可以用size_t類型來表示,迭代子之間的距離可以用ptrdiff_t來表示。現(xiàn)在我們被告知,你為什么不抽象的定義這些類型?這個要求比較高,
連語言本身都沒有抽象定義這些類型,而且c/c++數(shù)組還不能被這些類型定義所限定。我們發(fā)明了一個機制稱作"allocator",封裝了內(nèi)存模式的信
息。這個機制深刻地影響了庫中間的每一個組件。你可能疑惑:內(nèi)存模式和算法或者容器類接口有什么關(guān)系?如果你使用size_t這樣的東西,你就無法使用
t* 對象,因為存在不同的指針類型(t*, t huge *,
等等)。這樣你就不能使用引用,因為內(nèi)存模式不同的話,會產(chǎn)成不同的引用類型。這樣就會導致標準庫產(chǎn)生龐大的分支。
另外一件重要的事情是我們原先的關(guān)聯(lián)類型數(shù)據(jù)結(jié)構(gòu)被擴展了。這比較容易一些,但是最為標準的東西總是很困難的,因為我們做的東西人們要使用很多年。從容器
的觀點看,stl做了十分清楚的二分法設(shè)計。所有的容器類被分成兩種:順序的和關(guān)聯(lián)的,就好像常規(guī)的內(nèi)存和按內(nèi)容尋址的內(nèi)存一般。這些容器的語義十分清
楚。
當我到滑鐵盧以后,bjarne用了不少時間來安慰我不要太在意成敗與否,因為雖然看上去似乎不會成功,但是我們畢竟做到了最好。我們試過了,所以應該坦
然面對。成功的期望很低。我們估計大部分的意見將是反對。但是事實上,確實有一些反對意見,但不占上風?;F盧投票的結(jié)果讓人大跌眼鏡,80%贊成,
20%反對。所有人都預期會有一場惡戰(zhàn),一場大論戰(zhàn)。結(jié)果是確實有爭論,但投票是壓倒性的。
q: stl對于1994年2月發(fā)行的ansi/iso c++工作文件中的類庫有何影響?
a: stl被放進了滑鐵盧會議的工作文件里。stl文檔被分解成若干部分,放在了文件的不同部分中。mike
vilot負責此事。我并沒有過多地參與編輯工作,甚至也不是c++委員會的成員。不過每次有關(guān)stl的
建議都由我來考慮。委員會考慮還是滿周到的。
q: 委員會后來又做了一些有關(guān)模板機制的改動,哪些影響到了stl?
a:
在stl被接受之前,有兩個變化影響到了我們修訂stl。其一是模板類增加了包含模板函數(shù)的能力。stl廣泛地使用了這個特性來允許你建立各種容納容器的
容器。一個單獨的構(gòu)造函數(shù)就能讓你建立一個能容納list或其他容器的vector。還有一個模板構(gòu)造函數(shù),從迭代子構(gòu)造容器對象,你可以用一對迭代子當
作參數(shù)傳給它,這對迭代子之間的元素都會被用來構(gòu)造新的容器類對象。另一個stl用到的新特性是把模板自身當作模板參數(shù)傳給模板類。這項技術(shù)被用在剛剛提
到的allocator中。
q: 那么stl影響了模板機制嗎?
a: 在弗基山谷的會議中,bjarne建議給模板增加一個“局部特殊化”(partial
specialization)的特性。這個特性可以讓很多算法和類效率更高,但也會帶來代碼體積上的問題。我跟bjarne在這個建議上共同研究了一段
時間,這個建議就是為了使stl更高效而提出的。我們來解釋一下什么是“局部特殊化”。你現(xiàn)在有一個模板函數(shù) swap( t&,
t& ),用來交換兩個參數(shù)。但是當t是某些特殊的類型參數(shù)時,你想做一些特殊的事情。例如對于swap( int&,
int&
),你想用一種特別的操作來交換數(shù)據(jù)。這一點在沒有局部特殊化機制的情況下是不可能的。有了局部特殊化機制,你可以聲明一個模板函數(shù)如下:
template <class T> void swap( vector<T >&, vector<T> & );
這種形式給vector容器類的swap操作提供了一種特別的辦法。從性能的角度講,這是非常重要的。如果你用通用的形式去交換vector,會使用三個
賦值操作,vector被復制三次,時間復雜度是線性的。然而,如果我們有一個局部特殊化的swap版本專門用來交換兩個vector,你可以得到一個時
間復雜度為常數(shù)的,非常快的操作,只要移動vector頭部的兩個指針就ok。這能讓vector上的sort算法運行得更快。沒有局部特殊化,讓某一種
特殊的vector,例如vector<int>運
行得更快的唯一辦法是讓程序員自己定一個特殊的swap函數(shù),這行得通,但是加重了程序員的負擔。在大部分情況下,局部特殊化機制能夠讓算法在某些通用類
上表現(xiàn)得更高效。你有最通用的swap,不那么通用的swap,更不通用的swap,完全特殊的swap這么一系列重載的swap,然后你使用局部特殊
化,編譯器會自動找到最接近的那個swap。另一個例子copy?,F(xiàn)在我們的copy就是通過迭代子一個一個地拷貝。使用模板特殊化可以定義一個模板函
數(shù):
template <class t> t** copy( t**, t**, t** );
這可以用memcpy高效地拷貝一系列指針來實現(xiàn),因為是指針拷貝,我們可以不必擔心構(gòu)造對象和析構(gòu)對象的開銷。這個模板函數(shù)可以定義一次,然后供整個庫
使用,而且用戶不必操心。我們使用局部特殊化處理了一些算法。這是個重要的改進,據(jù)我所知在弗基山谷會議上得到了好評,將來會成為標準的一部分。(后來的
確成了標準的一部分 —— 譯者)
q: 除了標準類庫外,stl對那一類的應用程序來說最有用處?
a:
我希望stl能夠引導大家學習一種新的編程風格:通用編程。我相信這種風格適用于任何種類的應用程序。這種風格就是:用最通用的方式來寫算法和數(shù)據(jù)結(jié)構(gòu)。
這些結(jié)構(gòu)所要求的語義特性應該能夠被清楚地歸類和分類,而這些歸類分類的原則應該是任何對象都能滿足的。理解和發(fā)展這種技術(shù)還要很長時間,stl不過是這
個過程的起點。
我們最終會對通用的組件有一個標準的分類,這些組件具有精心定義的接口和復雜度。程序員們將不必在微觀層次上編程。你再也不用去寫一個二分查找算法。就是
在現(xiàn)在,stl也已經(jīng)提供了好幾個通用的二分查找算法,凡是能用二分查找算法的場合,都可以使用這些算法。算法所要求的前提條件很少:你只要在代碼里使用
它。我希望所有的組件都能有這么一天。我們會有一個標準的分類,人們不用再重復這些工作。
這就是douglas
mcilroy的夢想,他在1969年關(guān)于“構(gòu)件工廠”的那篇著名文章中所提出來的東西。stl就是這種“構(gòu)件工廠”的一個范例。當然,還需要有主流的力
量介入這種技術(shù)的發(fā)展之中,光靠研究機構(gòu)不行,工業(yè)界應該想程序員提供組件和工具,幫助他們找到所需的組件,把組件粘合到一起,然后確定復雜度是否達到預
期。
q: stl沒有實現(xiàn)一個持久化(persistent)對象容器模型。map和multimap似乎是比較好的候選者,它們可以把對象按索引存入持久對象數(shù)據(jù)庫。您在此方向上做了什么工作嗎,或者對這類實現(xiàn)有何評論?
a:很多人都注意到這個問題。stl沒實現(xiàn)持久化是有理由的。stl在當時已經(jīng)是能被接受的最巨大的庫了。再大一點的話,我認為委員會肯定不會接受。當然
持久化是確實是一些人提出的問題。在設(shè)計stl,特別是設(shè)計allocator時,bjarne認為這個封裝了內(nèi)存模式的組件可以用來封裝持久性內(nèi)存模
式。bjarne的洞察秋毫非常的重要和有趣,好幾個對象數(shù)據(jù)庫公司正在盯著這項技術(shù)。1994年10月我參加了object database
management
group的一個會議,我做了一個關(guān)于演說。他們非常感興趣,想讓他們正在形成中的組件庫的接口與stl一致,但不包括allocator在內(nèi)。不過該集
團的某些成員仔細分析了allocator是否能夠被用來實現(xiàn)持久化。我希望與stl接口一致的組件對象持久化方案能在接下來的一年里出現(xiàn)。
q:set,multiset,map和multimap是用紅黑樹實現(xiàn)的,您試過用其他的結(jié)構(gòu),比如b*樹來實現(xiàn)嗎?
a:我不認為b*適用于內(nèi)存中的數(shù)據(jù)結(jié)構(gòu),不過當然這件事還是應該去做的。應該對許多其他的數(shù)據(jù)結(jié)構(gòu),比如跳表(skip
list)、伸展樹(splay tree)、半平衡樹(half-balanced
tree)等,也實現(xiàn)stl容器的標準接口。應該做這樣的研究工作,因為stl提供了一個很好的框架,可以用來比較這些結(jié)構(gòu)的性能。結(jié)口是固定的,基本的
復雜度是固定的,現(xiàn)在我們就可一個對各種數(shù)據(jù)結(jié)構(gòu)進行很有意義的比較了。在數(shù)據(jù)結(jié)構(gòu)領(lǐng)域里有很多人用各種各樣的接口來實現(xiàn)不同的數(shù)據(jù)結(jié)構(gòu),我希望他們能用
stl框架來把這些數(shù)據(jù)結(jié)構(gòu)變成通用的。
(譯者注:上面所提到的各種數(shù)據(jù)結(jié)構(gòu)我以為大多并非急需,而一個stl沒有提供而又是真正重要的數(shù)據(jù)結(jié)構(gòu)是哈希結(jié)構(gòu)。后來在stepanov和matt
austern等人的sgi*stl中增補了hashset,hashmap和hashtable三種容器,使得這個stl實現(xiàn)才比較完滿。眾所周知,紅
黑樹的時間復雜度為o(logn), 而理想hash結(jié)構(gòu)為o(1)。當然,如果實現(xiàn)了持久化,b+樹也是必須的。)
q:有沒有編譯器廠商跟您一起工作來把stl集成到他們的產(chǎn)品中去?
a:是的,我接到了很多廠家的電話。borland公司的peter
becker出的力特別大。他幫助我實現(xiàn)了對應borland編譯器的所有內(nèi)存模式的allocator組件。symantec打算為他們的
macintosh編譯器提供一個stl實現(xiàn)。edison設(shè)計集團也很有幫助。我們從大多數(shù)編譯器廠商都得到了幫助。
(譯者注:以目前的stl版本來看,最出色的無疑是sgi*stl和ibm stl for
as/390,所有windows下的的stl實現(xiàn)都不令人滿意。根據(jù)測試數(shù)據(jù),windows下最好的stl運行在piii
500mhz上的速度遠遠落后與在250mhz
sgi工作站(irix操作系統(tǒng))上運行的sgi*stl。以我個人經(jīng)驗,linux也是運行stl的極佳平臺。而在windows的stl實現(xiàn)中,又以
borland c++builder的rogue wave stl為最差,其效率甚至低于jit執(zhí)行方式下的java2。visual
c++中的stl是著名大師p. j. plauger的個人作品,性能較好,但其queue組件效率很差,慎用)
q:stl包括了對ms-dos的16位內(nèi)存模式編譯器的支持,不過當前的重點顯然是在32位上線性內(nèi)存模式(flat model)的操作系統(tǒng)和編譯器上。您覺得這種面向內(nèi)存模式的方案以后還會有效嗎?
a:拋開intel的體系結(jié)構(gòu)不談,內(nèi)存模式是一個對象,封裝了有關(guān)指針的信息:這個指針的整型尺寸和距離類型是什么,相關(guān)的引用類型是什么,等等。如果
我們想利用各種內(nèi)存,比如持久性內(nèi)存,共享內(nèi)存等等,抽象化的工作就非常重要了。stl的一個很漂亮的特性是整個庫中唯一與機器類型相關(guān)的部分——代表真
實指針,真實引用的組件——被封裝到大約16行代碼里,其他的一切,容器、算法等等,都與機器無關(guān)(真是牛啊?。囊浦驳挠^點看,所有及其相關(guān)的東西,
象是地址記法,指針等,都被封裝到一個微小的,很好理解的機制里面。這樣一來,allocator對于stl而言就不是那么重要了,至少不像對于基本數(shù)據(jù)
結(jié)構(gòu)和算法的分解那么重要。
q:ansi/iso c標準委員會認為像內(nèi)存模式這類問題是平臺相關(guān)的,沒有對此做出什么具體規(guī)定。c++委員會會不會采取不同的態(tài)度?為什么?
a:我認為stl在內(nèi)存模式這一點上跟c++標準相比是超前的。但是在c和c++之間有著顯著的不同。c++有構(gòu)造函數(shù)和new操作符來對付內(nèi)存模式問
題,而且它們是語言的一部分?,F(xiàn)在看來似乎讓new操作符像stl容器使用allocater那樣來工作是很有意義的。不過現(xiàn)在對問題的重要性不像stl
出現(xiàn)之前那么顯著了,因為在大多數(shù)場合,stl數(shù)據(jù)結(jié)構(gòu)將讓new失業(yè)。大部分人不再需要分配一個數(shù)組,因為stl在做這類事情上更為高效。要知道我對效
率的迷信是無以復加的,可我在我的代碼里從不使用new,匯編代碼表明其效率比使用new時更高。隨著stl的廣泛使用,new會逐漸淡出江湖。而且
stl永遠都會記住回收內(nèi)存,因為當一個容器,比如vector退出作用域時,它的析構(gòu)函數(shù)被調(diào)用,會把容器里的所有東西都析構(gòu)。你也不必再擔心內(nèi)存泄漏
了。stl可以戲劇性地降低對于垃圾收集機制的需求。使用stl容器,你可以為所欲為,不用關(guān)心內(nèi)存的管理,自有stl構(gòu)造函數(shù)和析構(gòu)函數(shù)來對付。
q:c++標準庫子委員會正在制訂標準名空間(namespace)和異常處理機制。stl類會有名空間嗎,會拋出異
常嗎?
a:是的。該委員會的幾個成員正在考慮這件事,他們的工作非常卓越。
q:現(xiàn)在的stl跟最終作為標準的stl會有多大不同?委員會會不會干預某些變化,新的設(shè)計會不會被嚴格地控
制起來?
a:多數(shù)人的意見看起來是不希望對stl做任何重要的改變。
q:在成為標準之前,程序員們怎樣的一些stl經(jīng)驗?
a:他們可以從butler.hpl.hp.com/stl當下stl頭文件,在borland和ibm或其他足夠強勁的的編譯器中使用它。學習這種編程技術(shù)的唯一途徑是編程,看看范例,試著用這種技術(shù)來編程。
q:您正在和p. j. plauger合作一本stl的書。那本書的重點是什么?什么時候面世?
a:計劃95年夏天面世,重點是對stl實現(xiàn)技術(shù)的詳解,跟他那本標準c庫實現(xiàn)和標準c++庫實現(xiàn)的書類似。他是這本書的第一作者。該書可以作為stl的參考手冊。我希望跟bjarne合作另寫一本書,在c++/stl背景下介紹語言與庫的交互作用。
好多工作都等著要做。為了stl的成功,人們需要對這種編程技術(shù)進行更多的試驗性研究,更多的文章和書籍應該對此提供幫助。要準備開設(shè)此類課程,寫一些入門指南,開發(fā)一些工具幫助人們漫游stl庫。stl是一個框架,應該有好的工具來幫助使用這個框架。
(譯者注:他說這番話時,并沒有預計到在接下來的幾年里會發(fā)生什么。由于internet的大爆炸和java、vb、delphi等語言的巨大成功,工業(yè)
界的重心一下子從經(jīng)典的軟件工程領(lǐng)域轉(zhuǎn)移到internet上。再加上標準c++直到98年才制訂,完全符合要求的編譯器直到現(xiàn)在都還沒有出現(xiàn),stl并
沒有立刻成為人們心中的關(guān)注焦點。他提到的那本書也遲遲不能問世,直到前幾天(2001年元旦之后),這本眾人久已期盼的書終于問世,由p. j.
plauger, alexander stepanov, meng lee, david musser四大高手聯(lián)手奉獻,prentice
hall出版。不過該書主要關(guān)注的是stl的實現(xiàn)技術(shù),不適用于普通程序員。
另外就p. j.
plauger做一個簡介:其人是標準c中stdio庫的早期實現(xiàn)者之一,91年的一本關(guān)于標準c庫的書使他名滿天下。他現(xiàn)在是c/c++ use‘s
journal的主編,與microsoft保持著良好的,甚至是過分親密的關(guān)系,visual
c++中的stl和其他的一些內(nèi)容就是出自他的那只生花妙筆。不過由于跟ms的關(guān)系已經(jīng)影響到了他的中立形象,現(xiàn)在有不少人對他有意見。
至于stepanov想象中的那本與stroustrup的書,起碼目前是沒聽說。其實這兩位都是典型的編程圣手,跟ken
thompson和dennis
ritchie是一路的,懶得親自寫書,往往做個第二作者。如果作為第一作者,寫出來的書肯定是學院味十足,跟標準文件似的,不適合一般程序員閱讀。在計
算機科學領(lǐng)域,編程圣手同時又是寫作高手的人是鳳毛麟角,最著名的可能是外星人d. e. knuth, c++領(lǐng)域里則首推前面提到的andrew
koenig??上覀冎袊绦騿T無緣看到他的書。)
q:通用編程跟oop之間有什么關(guān)系?
a:一句話,通用編程是oop基本思想的自然延續(xù)。什么是oop的基本思想呢?把組件的實現(xiàn)和接口分開,并且讓組件具有多態(tài)性。不過,兩者還是有根本的不
同。oop強調(diào)在程序構(gòu)造中語言要素的語法。你必須得繼承,使用類,使用對象,對象傳遞消息。gp不關(guān)心你繼承或是不繼承,它的開端是分析產(chǎn)品的分類,有
些什么種類,他們的行為如何。就是說,兩件東西相等意味著什么?怎樣正確地定義相等操作?不單單是相等操作那么簡單,你往深處分析就會發(fā)現(xiàn)“相等”這個一
般觀念意味著兩個對象部分,或者至少基本部分是相等的,據(jù)此我們就可以有一個通用的相等操作。再說對象的種類。假設(shè)存在一個順序序列和一組對于順序序列的
操作。那么這些操作的語義是什么?從復雜度權(quán)衡的角度看,我們應該向用戶提供什么樣的順序序列?該種序列上存在那些操作?那種排序是我們需要的?只有對這
些組件的概念型分類搞清楚了,我們才能提到實現(xiàn)的問題:使用模板、繼承還是宏?使用什么語言和技術(shù)?gp的基本觀點是把抽象的軟件組件和它們的行為用標準
的分類學分類,出發(fā)點就是要建造真實的、高效的和不取決于語言的算法和數(shù)據(jù)結(jié)構(gòu)。當然最終的載體還是語言,沒有語言沒法編程。stl使用c++,你也可以
用ada來實現(xiàn),用其他的語言來實現(xiàn)也行,結(jié)果會有所不同,但基本的東西是一樣的。到處都要用到二分查找和排序,而這就是人們正在做的。對于容器的語義,
不同的語言會帶來輕微的不同。但是基本的區(qū)別很清楚是gp所依存的語義,以及語義分解。例如,我們決定需要一個組件swap,然后指出這個組件在不同的語
言中如果工作。顯然重點是語義以及語義分類。而oop所強調(diào)的(我認為是過分強調(diào)的)是清楚的定義類之間的層次關(guān)系。oop告訴了你如何建立層次關(guān)系,卻
沒有告訴你這些關(guān)系的實質(zhì)。
(這段不太好理解,有一些術(shù)語可能要過一段時間才會有合適的中文翻譯——譯者)
q:您對stl和gp的未來怎么看?
a:我剛才提到過,程序員們的夢想是擁有一個標準的組件倉庫,其中的組件都具有良好的、易于理解的和標準的接口。為了達成這一點,gp需要有一門專門的科
學來作為基礎(chǔ)和支柱。stl在某種程度上開始了這項工作,它對于某些基本的組件進行了語義上的分類。我們要在這上面下更多的功夫,目標是要將軟件工程從一
種手工藝技術(shù)轉(zhuǎn)化為工程學科。這需要一門對于基本概念的分類學,以及一些關(guān)于這些基本概念的定理,這些定理必須是容易理解和掌握的,每一個程序員即使不能
很清楚的知道這些定理,也能正確地使用它。很多人根本不知道交換律,但只要上過學的人都知道2+5等于5+2。我希望所有的程序員都能學習一些基本的語義
屬性和基本操作:賦值意味著什么?相等意味著什么?怎樣建立數(shù)據(jù)結(jié)構(gòu),等等。
當前,c++是gp的最佳載體。我試過其他的語言,最后還是c++最理想地達成了抽象和高效的統(tǒng)一。但是我覺得可能設(shè)計出一種語言,基于c和很多c++的
卓越思想,而又更適合于gp。它沒有c++的一些缺陷,特別是不會像c++一樣龐大。stl處理的東西是概念,什么是迭代子,不是類,不是類型,是概念。
說得更正式一些,這是bourbaki所說的結(jié)構(gòu)類型(structure
type),是邏輯學家所說的理念(theory),或是類型理論學派的人所說的種類(sort),這種東西在c++里沒有語言層面上的對應物(原文是
incarnation,直譯為肉身——譯者),但是可以有。你可以擁有一種語言,使用它你可以探討概念,精化概念,最終用一種非?!俺绦蚧? (programmatic,直譯為節(jié)目的,在這里是指符合程序員習慣的——譯者)的手段把它們轉(zhuǎn)化為類。當然確實有一些語言能處理種類(sorts),
但是當你想排序(sort)時它們沒什么用處。我們能夠有一種語言,用它我們能定義叫做foward
iterator(前向迭代子)的東西,在stl里這是個概念,沒有c++對應物。然后我們可以從forword
iterator中發(fā)展出bidirectional iterator(雙向迭代子),再發(fā)展出random
iterator??赡茉O(shè)計一種語言大為簡化gp,我完全相信該語言足夠高效,其機器模型與c/c++充分接近。我完全相信能夠設(shè)計出一種語言,一方面盡
可能地靠近機器層面以達成絕對的高效,另一方面能夠處理非常抽象化的實體。我認為該語言的抽象性能夠超過c++,同時又與底層的機器之間契合得天衣無縫。
我認為gp會影響到語言的研究方向,我們會有適于gp的實用語言。從這些話中你應該能猜出我下一步的計劃。