John Osborn 著(zhù)
7月,O’Reilly編輯John Osborn參加了微軟職業(yè)開(kāi)發(fā)者會(huì )議。在此,他對著(zhù)名的工程師、微軟.Net框架C#語(yǔ)言首席架構師Anders Hejlsberg進(jìn)行了采訪(fǎng)。Anders Hejlsberg因設計PCs上最早的語(yǔ)言之一—Turbo Pascal而廣為人知。他把Turbo Pascal許可給Borland公司,后又率隊創(chuàng )建了Delphi—一個(gè)極為成功的可視化的client/server應用設計工具。訪(fǎng)問(wèn)時(shí)在座的還有微軟C#產(chǎn)品經(jīng)理Tony Goodhew和O‘Reilly的Windows編輯Ron Petrusha。
Osborn:
我已經(jīng)看到一些關(guān)于C#(發(fā)音為"See sharp")的新聞故事,并注意到有很多似乎傾向于這樣的觀(guān)點(diǎn),或理論上說(shuō),C#不是Java的克隆就是Java的微軟替代品。如果你來(lái)做宣傳的話(huà),你希望人們怎么評論這門(mén)語(yǔ)言?
Hejlsberg:
首先,C#不是Java的克隆。在設計C#期間,我們考察了很多種語(yǔ)言,我們考察了C++,我們考察了Java,我們考察了Modula 2、C,我們還考察了Smalltalk。很多語(yǔ)言都有我們感興趣的相同的核心思想,比如深度面向對象、簡(jiǎn)化對象(object-simplification)等等。
C#和這些別的語(yǔ)言尤其是Java之間的關(guān)鍵不同點(diǎn)是,它非常接近C++,在我們的設計中努力使然。C#從C++直接借用了大多數的操作符、關(guān)鍵字和聲明。我們還保留了許多被Java拋棄的語(yǔ)言特性。為什么Java中沒(méi)有枚舉,道理何在?我的意思是,拋棄它們是基于何種理論基礎?在C++中,枚舉顯然是一個(gè)很有意義的概念。在C#中,我們保留了枚舉并同樣使其類(lèi)型安全。并且,枚舉不只是整型,它們實(shí)際上是從.NET基類(lèi)庫里的System.Enum派生下來(lái)的強類(lèi)型的值類(lèi)型。如果沒(méi)有進(jìn)行造型轉換,枚舉類(lèi)型“foo”和枚舉類(lèi)型“bar”不可互換。我認為這是個(gè)重要的差異。我們還保留了操作符重載和類(lèi)型轉換。C#名字空間的整體結構也非常接近C++。
但是,超越這些傳統的語(yǔ)言論題,我們設計語(yǔ)言的一個(gè)關(guān)鍵的目標是使C#面向組件。我們向語(yǔ)言自身加入了你在編寫(xiě)組件時(shí)所需要的所有概念。例如properties(屬性)、methods(方法)、events(事件)、attributes(特性)和documentation(文檔),它們都是一等的語(yǔ)言成分。我們對特性所做的工作是全新且具有創(chuàng )新意義的,利用特性可為任何對象加入有類(lèi)型的、可擴展的元數據。這在目前任何其它程序語(yǔ)言里都看不到。C#也是第一個(gè)合并XML注釋標簽的語(yǔ)言,編譯器可以用其直接從源碼中生成可讀的文檔。
另外一個(gè)重要的概念是我所說(shuō)的“一站購物式軟件”(one-stop-shopping software)。一旦你用C#寫(xiě)代碼,你就一體化地寫(xiě)了一切。不再需要頭文件、IDL(接口定義語(yǔ)言)文件、GUIDs和復雜的接口。因為它是自包容的單元,所以,一旦你能夠以這種方式編寫(xiě)自描述的代碼,你就可以把你的軟件嵌入到ASP頁(yè)面或植入各種不同的環(huán)境,這在以前是不可能的。
讓我們再回到這些關(guān)鍵的組件概念。語(yǔ)言是否應該支持屬性或事件,業(yè)界有很多爭論。沒(méi)錯,我們是可以用方法表達這種概念。我們可以用諸如“get”或“set”之類(lèi)的程序塊的命名模式,模擬屬性的行為。我們可以用接口和實(shí)現接口的適配器并轉發(fā)到對象。這都是可以實(shí)現的,正如同可以在C語(yǔ)言里進(jìn)行面向對象編程一樣。只是它更加困難,需要更多手工勞動(dòng),為了真正表達你的思想,你最終不得不去做所有的工作。我們認為是時(shí)候了,應該有門(mén)語(yǔ)言使得創(chuàng )建組件變得容易些。最近幾年來(lái),開(kāi)發(fā)人員在創(chuàng )建軟件組件。他們并不是創(chuàng )建整個(gè)應用或整個(gè)類(lèi)庫。每個(gè)人都是在創(chuàng )建從宿主環(huán)境提供的基組件繼承下來(lái)的組件。這些組件重載一些方法和屬性,它們處理事件,并把組件安裝回系統。樹(shù)立這些概念是關(guān)鍵的第一課。
Osborn:
你最近在介紹C#時(shí),第一張幻燈片上面寫(xiě)著(zhù):“C/C++家族里第一個(gè)面向組件的語(yǔ)言”。
Hejlsberg:
是的。這是我的首要目標之一。我們談?wù)撘磺腥绾味际菍ο?,這也非常關(guān)鍵。以前象Smalltalk和Lisp語(yǔ)言都可以這么做,但代價(jià)高昂。我認為C#包含一些優(yōu)美有趣的創(chuàng )新,以使得組件開(kāi)發(fā)容易些。例如裝箱和拆箱的概念。裝箱可以使一個(gè)值類(lèi)型的值轉換為一個(gè)對象,拆箱可以使一個(gè)對象轉換為一個(gè)簡(jiǎn)單類(lèi)型的值。這在以前或許也有,但我們把它應用于語(yǔ)言的方式是一種優(yōu)美的創(chuàng )新。
我們努力避免以“象牙塔”的方式設計C#和.Net框架。我們承受不起重寫(xiě)我們所有的軟件的負擔。業(yè)界也負擔不起,特別是今天我們正轉移到Internet時(shí)代。你要善于利用你已經(jīng)擁有的。所以,我認為互操作性也是關(guān)鍵的。我們致力于為程序員提供所有符合Internet標準的可互操作的恰當的解決方案,例如HTTP、HTML、XML以及業(yè)已存在的微軟技術(shù)。所以你不會(huì )有如墜深淵的那一刻—發(fā)現新的.NET框架下沒(méi)有提供你用的一些東西,或者當你意識到你想利用一些已經(jīng)存在的API或組件的時(shí)候。你已經(jīng)看到我們已把所有COM互操作能力內建入語(yǔ)言和通用運行時(shí);你已經(jīng)看到可以使用DllImport特性導入已存在的DLL(動(dòng)態(tài)連接庫);你已經(jīng)看到即使那些都不能遂你所愿,我們也有不安全代碼的概念。不安全代碼允許你編寫(xiě)使用指針的內聯(lián)C代碼,可以做不安全的造型轉換,可以抑制內存從而使其不會(huì )被意外地垃圾收集。
關(guān)于不安全代碼有很多爭論,人們似乎認為我們在吸毒或是在干什么別的壞事。我認為這是個(gè)誤會(huì )。代碼不會(huì )僅僅因為標記了“unsafe”就表示它不受管制。當然,我們不會(huì )扔出不安全的指針使人們容易受到從Internet下載的不安全代碼的攻擊。不安全代碼被深深地約束在安全系統里。我們提供這樣的彈性:1.呆在托管代碼箱里完成工作而不會(huì )墜入深淵;2.轉入一種不同的語(yǔ)言使用一種不同的編程模型編寫(xiě)本地代碼。如果你停留在這個(gè)箱子里,我們會(huì )使代碼更加安全,因為系統知道它要干什么。事實(shí)上,即使你編寫(xiě)不安全代碼也并不意味著(zhù)你離開(kāi)了托管空間。因此,你的不安全代碼會(huì )變得更能干。
Osborn:
請給我多講一些在托管環(huán)境里處理不安全代碼的機制。
Hejlsberg:
好的。描述托管執行環(huán)境比如Smalltalk、Java和.NET通用語(yǔ)言運行時(shí)一個(gè)重要特征是它們提供了垃圾收集機制。為了提供垃圾收集機制,至少要提供一個(gè)現代的垃圾收集器,一個(gè)“標記和清掃”垃圾收集器,比起傳統非托管代碼來(lái)說(shuō),你必須更多地了解正在執行的代碼。為了找出要排除的死對象,你必須能遍歷堆棧,找到所有活動(dòng)的根,并指出哪些對象是活動(dòng)的哪些是不再被訪(fǎng)問(wèn)的。然而,為了能夠達到這個(gè)目標,你必須和你執行的代碼緊密協(xié)作。代碼要具有更好的描述性。它要告訴你它是怎么分布在堆棧里的,它的局部變量在什么地方等等。
當你在C#中編寫(xiě)不安全代碼時(shí),你可以做不是類(lèi)型安全的事,比如指針操作。當然,標記為unsafe的代碼并非絕對執行在不可信任的環(huán)境里。為了使之執行,你必須授予信任,否則,代碼將不會(huì )執行。從這一點(diǎn)來(lái)看,和其它本地代碼并無(wú)區別,真正的區別是它們仍然運行在托管空間里。你編寫(xiě)的方法有一個(gè)描述表,它告訴你哪些對象是活動(dòng)的,因此,不管什么時(shí)候你進(jìn)入這些代碼,你都不必跨越列集邊界(marshalling boundary)。否則,當你進(jìn)入非描述性的、非托管代碼(比如通過(guò)Java本地接口),你不得不在堆棧上設置一個(gè)水印或設立一個(gè)屏障。你必須重新列集所有箱子外的引數(arguments)。一旦開(kāi)始使用對象,你必須對你觸及的東西小心翼翼,因為GC(垃圾收集器)仍然在另一個(gè)不同線(xiàn)程里運行。如果你不使用一些隱晦的方法鎖定對象從而正確地抑制垃圾收集器,它可能會(huì )移去對象。如果你忘記那么做,那你將會(huì )不走運。
我們采用了一種不同的方式。我們說(shuō)過(guò),“讓我們集成這個(gè)到語(yǔ)言中去。讓我們提供聲明,例如fixed聲明,它可以讓你抑制對象以和GC協(xié)作并集成之?!庇眠@種方法,我們提供最佳方式,帶領(lǐng)所有已經(jīng)存在的代碼一起向前,而不是僅僅將它們拋棄。這是一種不一樣的設計方式。
Osborn:
因此,你們處理的不安全代碼的內存,實(shí)際上是在垃圾收集器的監視之下?
Hejlsberg:
沒(méi)錯,是這樣。但是,就象所謂的“購者自慎,不包退換”一樣,它并不安全。你可以獲取指針并做錯事,當然,你在本地代碼里也能干同樣的錯事。
Osborn:
我認為另一個(gè)易混淆的地方,是理解C#在哪兒停止以及通用運行時(shí)從哪兒開(kāi)始。與它從通用運行時(shí)庫得到的相比,C#語(yǔ)言自身的創(chuàng )新是什么?
Hejlsberg:
好的,我想這個(gè)混淆來(lái)源于這樣一個(gè)事實(shí):當人們談?wù)揓ava時(shí),他們并不真的知道哪個(gè)是語(yǔ)言哪個(gè)是運行時(shí)。當人們談?wù)揓ava時(shí),某些混淆就發(fā)生了。哪個(gè)是語(yǔ)言哪個(gè)是運行時(shí)?當他們談?wù)揓ava時(shí),他們到底指的是什么?Java,語(yǔ)言?Java,語(yǔ)法?還是Java,平臺?人們將這些不同的方面混為一談。我們的方式表明我們想成為一個(gè)多語(yǔ)言的平臺。我們將創(chuàng )建一個(gè)平臺,它允許你進(jìn)行多語(yǔ)言編程,并且共享一套公共的API(應用編程接口)。讓我們承認這一點(diǎn),一些人喜歡用COBOL編程,一些人喜歡用Basic編程,一些人喜歡用C++,還有一些人將會(huì )喜歡用C#—我希望。但是,我們不會(huì )試圖告訴你,忘記你曾經(jīng)做過(guò)的所有的事情吧,我們不會(huì )說(shuō),“現在只有一種語(yǔ)言,在這個(gè)競賽中將不會(huì )有進(jìn)一步的創(chuàng )新了”。我們說(shuō)業(yè)界因為彈性而友好。Java是怎么來(lái)的?它的出現是因為在它前已經(jīng)存在一些編程語(yǔ)言,而在它后也還將會(huì )出現一些編程語(yǔ)言。我們想打造一個(gè)平臺,在此你可以偏愛(ài)某種語(yǔ)言但不會(huì )否定整個(gè)價(jià)值取向;我們想打造一個(gè)平臺,它可以是不斷革新的。今天誰(shuí)在幫助COBOL程序員?又是誰(shuí)將他們帶入WEB?只有在.NET平臺上你才可以把富士通COBOL嵌到ASP頁(yè)面中。我的意思是,它真正是革命性的!
Osborn:
假定.NET平臺支持多語(yǔ)言,那為什么選擇C#而不是Visual Basic、C++甚至COBOL?是什么使C#如此引人注目?
Hejlsberg:
首先,C#可以使我們從一張白紙開(kāi)始。也就是說(shuō),我們沒(méi)有任何向后兼容的負擔。這顯然會(huì )使事情簡(jiǎn)單些,無(wú)論從是從實(shí)現的立場(chǎng)還是從使用的立場(chǎng)都是這樣。例如,在C#中,我們只有一種class,并且總是被垃圾收集。而另一方面,托管C++有兩套,因為它要保留非垃圾收集風(fēng)格的程序設計。因此,在C#中,只需要你理解一些簡(jiǎn)單的概念。
語(yǔ)言是一個(gè)有趣的東西,它是一種口味;語(yǔ)言又是一件嚴肅的事情,它是程序員選擇的一種生活方式。我是指,我們意識到我們不能走出來(lái)說(shuō),“這兒有個(gè)平臺,你只可以使用一種語(yǔ)言?!奔词乖谀莻€(gè)平臺上用一種語(yǔ)言可以干所有的事情,人們可能還是不喜歡它的語(yǔ)法,他們可能喜歡大括號或者一些別的程序塊分界符。那是他們熟悉的。那是使他們感覺(jué)舒服并且富有生產(chǎn)力和能力的。我們對待C#的方式僅僅是為認為語(yǔ)言太復雜的C++程序員和認為丟失了一些C和C++語(yǔ)言特性的Java程序員提供一個(gè)替代品。我們尋求一個(gè)簡(jiǎn)化C++的方式并投入到一個(gè)多語(yǔ)言的平臺中,它提供更大的互操作性,并且提供完備的組件概念等等。
Goodhew:
一件有趣的事情來(lái)自于我們對開(kāi)發(fā)者跟蹤調查,60%以上的職業(yè)開(kāi)發(fā)人員使用兩種或更多的語(yǔ)言去創(chuàng )建他們的應用。特別是當我們問(wèn)他們都用哪些開(kāi)發(fā)工具的時(shí)候,我們得到的答案是:沒(méi)有哪一種面向對象的語(yǔ)言將會(huì )是終結者并且所有程序員都會(huì )使用它。正如Anders早先所說(shuō),人們期望某種能夠滿(mǎn)足他們所做的事或他們的感覺(jué)的語(yǔ)法。這是一種個(gè)人選擇,這也是整個(gè).NET平臺所關(guān)心的—提供給開(kāi)發(fā)者一個(gè)語(yǔ)言實(shí)現選擇。我想我們做了件漂亮的工作。你基本上可以在Visual Basic.NET和C#中做同樣的事情。Visual Basic對于大多數程序員來(lái)說(shuō)仍然是易于接受的。C#則具有更多的活動(dòng)空間并且比VB更富威力。
Osborn:
這意味著(zhù)在C#中可用更少的聲明實(shí)現更多?
Hejlsberg:
是的。意味著(zhù)通過(guò)不安全代碼,你可以得到更多的能力。
Osborn:
也就是說(shuō),不能在VB中寫(xiě)不安全代碼?
Hejlsberg:
是的。不可以。
Goodhew:
但是,基本上,兩種語(yǔ)言可以做同樣的事。和Visual Studio 6相比,這是一個(gè)根本性的改變。在Visual studio 6.0中,如果你想創(chuàng )建多線(xiàn)程的MTS對象,并且你是一個(gè)VB程序員,你就沒(méi)招。你不得不用C++?,F在,有了.NET框架,你可以使用任何一種你喜歡的語(yǔ)言。
Hejlsberg:
這就是我在一般會(huì )議談話(huà)里說(shuō)過(guò)的,.NET框架提供一致的編程模型。在語(yǔ)言和框架的進(jìn)化過(guò)程中,我們似乎一貫都是把一種程序語(yǔ)言綁死在特定的API和特定的編程方式上。VB是快速應用開(kāi)發(fā)工具;MFC(微軟基礎類(lèi))是子類(lèi)化的方式;ASP則是把東西塞到Web頁(yè)面中。在每一種情況下,你對編程模型的選擇總是決定了你對程序語(yǔ)言和可使用的API的選擇。每次當你變換框架時(shí),都增加了你學(xué)習新語(yǔ)言和API負擔的工作量。我們真正試圖統一這一切,我們提供一套API,一套支持可視化設計的工具,我們還提供一個(gè)可以任選一種適合你的語(yǔ)言的彈性。
Osborn:
我不知道這對那些使用象VBScript和Jscript腳本語(yǔ)言的有什么用?
Hejlsberg:
.NET框架下奇妙的事情之一是使腳本語(yǔ)言能夠編譯??纯碅SP+(譯注:今天稱(chēng)為ASP.NET),現在,實(shí)際上,在你的頁(yè)面里運行的是真正編譯過(guò)的代碼。它不是遲綁定的、調度查找的—如果用戶(hù)沒(méi)有點(diǎn)擊頁(yè)面,你就不會(huì )看到運行時(shí)錯誤。ASP+開(kāi)發(fā)者可以使用Visual Basi.NET完全的威力而不是VBScript。并且第一次,他們可以使用Perl、Python以及其它流行語(yǔ)言,如果他們這么選擇的話(huà)。
Petrusha:
服務(wù)端的JavaScript現在也能被編譯?
Hejlsberg:
是的,沒(méi)錯。
Goodhew:
.NET框架使得使用腳本語(yǔ)言就象用具有完全特性的語(yǔ)言一樣,因為它們現在訪(fǎng)問(wèn)的是一個(gè)真正的編程框架,并且訪(fǎng)問(wèn)的是同一基類(lèi)API。你應該看看搞JScript實(shí)現的伙計們都已經(jīng)完成了什么。(編注:JScript是微軟對ECMA 262語(yǔ)言規范(ECMAScript 版本 3)的實(shí)現,只有一些很小的例外(為了保持向后的兼容性),JScript是對ECMA標準的完整實(shí)現)。所以.NET平臺提供了一個(gè)通用語(yǔ)言框架,對腳本寫(xiě)作者來(lái)說(shuō),具有極大的好處。
Osborn:
我們已經(jīng)討論關(guān)于Java、C++和腳本語(yǔ)言。在PDC上,我聽(tīng)到很多人爭論.NET IL(IL是微軟中間語(yǔ)言,所有編譯器都必須產(chǎn)生它以運行在.NET框架上)和運行于Java虛擬機中的Java字節碼沒(méi)什么兩樣。從你的談話(huà)中,顯然你并不同意這一點(diǎn)。你介意進(jìn)一步評論它們之間的區別嗎?
Hejlsberg:
我當然不同意這種說(shuō)法。首先,ILs的思想是一種非常老的思想了。你可以追溯這個(gè)概念到UCSD Pascal p-machine(一個(gè)早期的個(gè)人計算機Pascal實(shí)現)或者Smalltalk。P-code曾被Basic和Visual Basic使用,Word的一個(gè)組成部件,內部使用p-code引擎,因為它更精簡(jiǎn)。所以,p-code根本就不是什么新玩意。
我認為,我認為我們使用的IL的方式對此感興趣:我們給你一個(gè)選擇—如果你愿意—你可以控制將IL編譯或翻譯為本地代碼的時(shí)機。實(shí)際上,使用managed C++,你可以直接從源程序生成本地代碼。Managed C++還可以生成IL,就象C#和VB那樣。當你安裝你的代碼時(shí),我們給你一個(gè)編譯選項,可以把IL編譯成本地代碼。因此,當你運行它們時(shí),就不會(huì )有即時(shí)編譯負擔。我們還給你提供了一個(gè)動(dòng)態(tài)運行和編譯代碼的選項:即時(shí)編譯。有了IL,就給你帶來(lái)了很多便利,比如它提供了這些能力:移植到不同的CPU架構,引入真正的類(lèi)型安全,并在此之上構建安全系統。
我認為我們的IL設計和Java字節碼關(guān)鍵區別在于,我們做出了超前的決定—不用解釋器。我們的代碼永遠本地運行。因此,即使產(chǎn)生IL,你也從來(lái)都不會(huì )運行解釋器。我們甚至還提供了不同風(fēng)格的JITs。對于精簡(jiǎn)框架(compact framework),我們有EconnoJIT,就象我們稱(chēng)呼它的一樣,它是一個(gè)非常簡(jiǎn)單的JIT(編注:.NET Compact是.NET framework的一個(gè)子集,是為移植到其它設備和平臺而設計的)。對于桌面版,我們有完備功能的JIT。我們甚至有可和我們的C++編譯器共用一個(gè)后端的JIT。不過(guò),這都會(huì )比較耗時(shí),因此你只應該在安裝時(shí)使用它們。
一旦你做出偏向于執行本地代碼而不是解釋代碼的決策,它就會(huì )強烈地影響IL的設計。它改變了應該包括那些指令,應該包括哪些類(lèi)型信息,以及它應該如何表達。如果你仔細看看兩種IL(譯注:即.NET IL和Java字節碼),你就會(huì )注意到它們很不一樣。從某種意義上講,我們的IL是類(lèi)型中立的。指令里沒(méi)有指定引數類(lèi)型的信息。進(jìn)一步來(lái)說(shuō),它是靠已經(jīng)壓棧的東西推斷出來(lái)的。這種方式使IL更為精簡(jiǎn)。無(wú)論如何,一個(gè)JIT編譯器需要知道那些信息,因此沒(méi)有理由在指令里攜帶它們。所以,我們最終做出了不一樣的設計決策,而這使得容易把IL翻譯成本地代碼。
Osborn:
解釋方式和你描述的方式有何不同?
Hejlsberg:
解釋器的核心是一個(gè)循環(huán)—從p-code流取得一些字節,然后進(jìn)入一個(gè)大大的switch聲明,“哦,這是ADD指令,因此它到這兒來(lái),但這不是…”等等。
解釋器模擬CPU。我們反其道而行之,我們只走一條道,我們一直都走一條道,我們把指令翻譯為機器碼?,F在,在EconoJIT的情況下,機器碼實(shí)際上非常簡(jiǎn)單,它只創(chuàng )建一個(gè)調用和壓棧指令的列表,并且調用運行時(shí)輔助器,然后運行時(shí)輔助器引發(fā)這個(gè)列表。當然,這個(gè)代碼比解釋的代碼執行得快。
Osborn:
讓我用一句話(huà)來(lái)總結一下:你們完全編譯代碼。因此當你編譯完時(shí),bits已經(jīng)完全準備好運行了,盡管從IL翻譯成機器碼的時(shí)機可能不一樣。
Hejlsberg:
是的。但是,如果是在一個(gè)內存受限的小設備的環(huán)境里,運行完就可將代碼丟棄掉。
Osborn:
讓我們進(jìn)入語(yǔ)言的語(yǔ)法細節。我在想,C#是否包括對正則表達式的內建支持。我沒(méi)有在語(yǔ)言參考里看到它,或許它可能在別的什么地方吧。
Hejlsberg:
首先,在基類(lèi)庫里有一個(gè)正則表達式類(lèi)。我們并沒(méi)有在語(yǔ)言里加入對正則表達式的任何直接支持,但是,實(shí)際上我們有些非常類(lèi)似的特性。并不值得對它們做重大的處理。但是,比方說(shuō),當你需要指定一個(gè)時(shí)候,我們給你這個(gè)能力:逐個(gè)字寫(xiě)一個(gè)字符串而無(wú)需每次寫(xiě)兩個(gè)后斜杠。當你寫(xiě)正則表達式時(shí),并且當你的正則表達式里的引號還套引號時(shí),它實(shí)際上有很大的幫助。雖然就總體而言,這點(diǎn)幫助不足掛齒,但顯然其核心在.NET框架之中,而這個(gè)框架可以被任何編程語(yǔ)言共享。
Osborn:
C#和Java名字空間看起來(lái)不同。它們是否概念相同而實(shí)現上不同?
Hejlsberg:
概念上是的,但是在實(shí)現上,差別很大。在Java里,包的名字也是物理意義上的東西,它指示了你的源代碼文件的目錄結構。在C#中,物理包和邏輯名稱(chēng)完全獨立,無(wú)論你如何稱(chēng)呼你的名字空間,它都和你的實(shí)際代碼的物理包不相關(guān)。這就給你更多的彈性—將物理上分布的單元包裝在一起,并且不強迫你建很多的目錄。在語(yǔ)言自身,有一些很明顯的區別。在Java里,包也是你的物理結構,因此,Java源文件必須在正確的路徑里,并且只能包含一個(gè)公用類(lèi)型或者一個(gè)公用類(lèi)。因為C#沒(méi)有那種物理和邏輯上的綁定,所以你可以任意命名你的源文件。每一個(gè)源文件都可以被多個(gè)名字空間使用并且可以帶有多個(gè)公用類(lèi)。進(jìn)一步而言,假如你喜歡的話(huà),你可以把所有的源碼寫(xiě)在一個(gè)大文件里,或者可以把它們分散到的小文件中去。概念上講,C#編譯時(shí)發(fā)生了什么—你給編譯器提供了所有構成你的項目的源文件,然后它只管前進(jìn)并指出該干什么。
Osborn:
我有一個(gè)關(guān)于泛型編程的問(wèn)題:你認為它是個(gè)重要的概念嗎?它應該成為面向對象語(yǔ)言的一部分嗎?如果是的話(huà),你們把泛型編程加為C#的一部分的計劃如何?
Goodhew:
唔,在第一個(gè)版本里納入泛型編程的愿望受到了限制。因為,并不象每一個(gè)人以為的那樣,微軟并沒(méi)有無(wú)限的資源。對于在這第一個(gè)版本里該有些什么東西,我們不得不做出一些困難的決定。
Osborn:
有多少人參與開(kāi)發(fā)C#?
Hejlsberg:
語(yǔ)言設計組由4個(gè)人構成,編譯器組由另外五個(gè)開(kāi)發(fā)人員構成。
Petrusha:
框架呢?
Hejlsberg:
那就多了,整個(gè)公司都被卷進(jìn)來(lái)了。
Goodhew:
就整個(gè)Visual Studio和.NET平臺團隊而言,我們的部門(mén)大概有千人左右。包括程序管理人員、開(kāi)發(fā)人員、測試人員,包括所有構建函數、框架、運行時(shí)、ASP編程模型的人員以及其它所有的人,比方說(shuō),我自己,管理層的。
Hejlsberg:
就你剛才所說(shuō)的泛型方面,我明確地認為它是個(gè)非常有用的概念,并且你當然可以列舉出發(fā)生在學(xué)術(shù)界和業(yè)界所有的泛型研究。模板是該問(wèn)題的一種解決方案。在我們內部討論中,我們決定要在新平臺里做這件事情。但我們真正喜歡做的是讓泛型能夠被底層的運行時(shí)所理解。這和如何創(chuàng )建泛型原型是不同的。使用Java的“擦除”概念,系統里沒(méi)有真正的泛型信息。如果通用語(yǔ)言運行時(shí)理解泛型的概念,多種語(yǔ)言就可以共享這個(gè)功能。你可以在一個(gè)地方用C#寫(xiě)一個(gè)泛型類(lèi),別的人用別的語(yǔ)言也可以使用它。
使泛型成為運行時(shí)的一部分,還可以使你能夠更有效率地做某些事情。泛型實(shí)例化的最理想的時(shí)間是在運行時(shí)。如果用C++,模板的實(shí)例化發(fā)生在編譯時(shí),你有兩種選擇:聽(tīng)任你的代碼膨脹或試圖在鏈接時(shí)去除掉一些膨脹代碼。但是,如果你有多個(gè)應用,你可能會(huì )忘記這一點(diǎn),你將只能得到膨脹的代碼。
如果把泛型的知識納入通用語(yǔ)言運行時(shí),那么,運行時(shí)就可以理解—當一個(gè)應用或組件請求一個(gè)“Foo”列表時(shí),它首先會(huì )問(wèn):“我已經(jīng)有了一個(gè)實(shí)體化的“Foo”列表了嗎?”如果是,就用那一個(gè)。實(shí)際上,如果Foo是一個(gè)引用類(lèi)型,并且我們設計得當的話(huà),我們可以讓所有引用類(lèi)型共享一個(gè)實(shí)體。對于值類(lèi)型,比如整型和浮點(diǎn)型,我們可以為每一個(gè)值類(lèi)型創(chuàng )建一個(gè)實(shí)體,但這應該在應用請求時(shí)才做。為了把泛型加入運行時(shí),我們已經(jīng)做了大量的設計工作和必要的基礎性工作。
你先前提到的關(guān)于IL的東西是有意思的,因為加入泛型的決定影響了IL的設計。如果IL指令嵌入類(lèi)型信息,比方說(shuō),假如一個(gè)“加”指令不再是個(gè)“加”了,而是一個(gè)整數“加”或是浮點(diǎn)數“加”或是一個(gè)雙精度數“加”,你就把類(lèi)型信息硬加入到了指令流里,在這一點(diǎn)來(lái)說(shuō),IL不是泛型的。我們的IL格式實(shí)際上是真正的類(lèi)型中立的。并且,為了保持類(lèi)型中立,我們可以遲些時(shí)候加入泛型且不會(huì )給我們帶來(lái)麻煩,至少不會(huì )太麻煩。這也是我們的IL和Java的字節碼看起來(lái)不一樣的原因之一。我們IL類(lèi)型中立?!凹印敝噶羁梢约訔m數娜魏蝺蓚€(gè)東西。在泛型世界,當它被實(shí)體化時(shí),它可以被轉換成不同的代碼。
Osborn:
所有.NET語(yǔ)言都可獲得泛型能力嗎?
Hejlsberg:
是的。微軟劍橋研究院已經(jīng)創(chuàng )建了一個(gè)支持泛型能力的通用語(yǔ)言運行時(shí)和C#編譯器的版本,我們正在研究如何盡快使其前進(jìn)。第一個(gè)版本是不可能加入泛型了,我們知道的就這么多。但是我們正在工作,以確保我們在第一個(gè)版本里做了正確的事情,從而使泛型可以適用于整個(gè)藍圖。
Osborn:
C#和.NET框架以及Visual Studio的下一個(gè)版本計劃發(fā)行日期是?
Goodhew:
唔,我們?yōu)閬?lái)這兒參加PDC的6500名人員帶來(lái)了技術(shù)預覽版。我們希望2000年秋季的某個(gè)時(shí)間發(fā)布beta版,然后在準備好以后,我們發(fā)布正式版。我們所做的一件真正令人激動(dòng)的事情是看看Windows2000發(fā)行版發(fā)布進(jìn)行的如何,以讓關(guān)鍵客戶(hù)參與到合作開(kāi)發(fā)和合作部署的進(jìn)程中來(lái)。關(guān)于.NET框架和Visual Studio.NET,我們將再次和客戶(hù)協(xié)作,以決定最終產(chǎn)品的發(fā)行日期。我們打算讓他們告訴我們什么時(shí)候產(chǎn)品該就緒了。并且,因為有真正的客戶(hù)參與到這個(gè)進(jìn)程中來(lái),我們應將獲得更好的產(chǎn)品質(zhì)量。這種做法的不利的一面是使產(chǎn)品開(kāi)發(fā)和發(fā)布的進(jìn)程有點(diǎn)不確定。但這是一種根本性的改變。我們正在尋找一種打破質(zhì)量障礙的產(chǎn)品發(fā)行方式,而不僅僅是挑一個(gè)武斷的日期說(shuō)我們要發(fā)貨了。
Osborn:
因此,不是一個(gè)代碼完成的日期,我們正在尋找一個(gè)“準備好出發(fā)”的日期?
Goodhew:
是的,沒(méi)錯。我認為開(kāi)發(fā)者將會(huì )發(fā)現Visual Studio.Net發(fā)行版是微軟歷史中最高質(zhì)量的發(fā)行版本之一。
Osborn:
你們已經(jīng)把C#提交給ECMA(譯注:歐洲計算機制造商協(xié)會(huì ))。標準化真的是一個(gè)嚴肅的目標嗎?你希望在其它平臺上也可使用C#嗎?
Hejlsberg:
的確如此!把C#作為一個(gè)可能的標準提供給業(yè)界當然是我們的目標,這也是我們把它提交給ECMA的原因之一。在引導這個(gè)有著(zhù)通用語(yǔ)言基礎設施的公共設計的語(yǔ)言的進(jìn)程中,(??)我們當然希望得到ECMA的支持。關(guān)于通用基礎設施,我的意思是指這個(gè)規范所規定的一套核心類(lèi)庫集,如果其它公司使用其它平臺實(shí)現它,他們有理由期望發(fā)現可以在他們的程序里利用這些類(lèi)。
Goodhew:
我想指出的是我們正在和ECMA做真正的開(kāi)放標準。當ECMA為C#和通用語(yǔ)言基礎設施達成標準后,在ECMA的版權和許可政策下,真正的開(kāi)放將可實(shí)現。任何客戶(hù)、任何人都可以許可ECMA C#標準,子集之,超集之,并且無(wú)需付版稅。他們可以在任何平臺上或任何設備上實(shí)現之。我們完全希望人們那么做。這和我們的競爭者根本不同,他們徘徊在標準之外,尋找某某人去為他們私有的語(yǔ)言貼上印花。
John:
我在早餐和午餐時(shí)聽(tīng)說(shuō):“假如微軟沒(méi)有把COM搞到基礎設施中去,平臺會(huì )具有多么真正可能的可移植性?”
Hejlsberg:
完全可能。COM并非C#和通用語(yǔ)言基礎設施標準化之必須。根本不是。C#有一個(gè)完備豐富的類(lèi)模型,而COM則是從另外一個(gè)視角看待應用的互操作性。但是,C#和通用運行時(shí)的核心中從未說(shuō)過(guò)必須要有COM、GUID、HRESULT、AddRef或Release等等。一個(gè)都沒(méi)有。.NET通用語(yǔ)言運行時(shí)徹底摒棄了COM,但它還是給了你巨大的COM互操作能力。鑒于先前所述,我仍然認為它將非常重要,但絕非不可或缺。
Goodhew:
我認為這些評論起因于我們公開(kāi)的最初版本的語(yǔ)言規范。微軟在某次會(huì )議上把它寫(xiě)進(jìn)了規范。在那次會(huì )議上,我們認為按照微軟平臺來(lái)說(shuō)這是非常重要的。結果,我們在規范里多次引用COM和DLL這樣東西。DLL是如何在已給定平臺上,激活本地代碼的更多的一般性問(wèn)題中的一個(gè)特例。對于納入標準化組織以及和象IBM的人(我們和他們一起制訂SOAP規范)協(xié)作的一個(gè)好處是,可以確保我們不做任何這樣的提及,以防止在規范的未來(lái)版本里,把我們自己綁死或鎖定在象COM框架這樣的東西上。
就象Anders說(shuō)的那樣,COM互操作能力和COM支持對我們和現有的微軟客戶(hù)來(lái)說(shuō)是極其重要的。我認為為了在.NET上支持COM我們做了偉大的工作。但是,業(yè)界的人們已經(jīng)閱讀了大量的我們對COM和DLL字眼引用的東西,他們由此推論.NET平臺僅僅是為Windows平臺而設計的,這絕對是錯誤的。
Hejlsberg:
并且,我認為就象COM互操作能力對于微軟和在微軟平臺上構建解決方案的客戶(hù)很重要一樣,C#和通用語(yǔ)言基礎設施的標準化,將允許在任何其它平臺上實(shí)現這門(mén)語(yǔ)言,以加入意義重大的平臺互操作能力。
Osborn:
所以你們將不會(huì )堅持應該有個(gè)什么“純C#”和“純.NET”的實(shí)現?
Hejlsberg:
什么叫“純”?真正有多少“純”Java應用存在?我冒險猜測一下,非常非常少。那就是我估計的數量。讓我們承認這一點(diǎn),人們希望能夠利用他們已有的代碼。不可能叫那些公司把什么東西都扔掉。
Goodhew:
你和Roger Sessions交流過(guò)嗎?(編注:Roger Sessions是ObjectWatch公司的總裁,并且是《COM+ and the Battle for the Middle Tier》的作者) 。
Osborn:
沒(méi)有。
Goodhew:
Roger談到了EJB(Enterprise JavaBeans)規范的相關(guān)章節,那兒講了廠(chǎng)商許可擴展。毫不奇怪,廠(chǎng)商擴展包括諸如事務(wù)管理、安全、消息技術(shù)以及其它更多的方面,這在構建企業(yè)級系統中是相當重要的。在一篇文章[譯注:http://www.objectwatch.com/issue_24.htm]里,Sessions粗略地列舉了11個(gè)領(lǐng)域的機能,這是可容許的廠(chǎng)商規范實(shí)現。因此,如果你選擇IBM Websphere作為你的EJB實(shí)現,你為你的EJB應用寫(xiě)的代碼將不可避免地把你鎖在Websphere上。Java是100%純和100%可移植的概念是不真實(shí)的。在IBM的開(kāi)發(fā)者工作站點(diǎn)上,有一個(gè)對James Gosling的偉大的專(zhuān)訪(fǎng)(譯注:http://www-106.ibm.com/developerworks/features/gosling/index.html)。James Gosling直接指出了這一點(diǎn)。他說(shuō),是的,整個(gè)“寫(xiě)一次到處運行”、“100%純的東西”真是個(gè)愚蠢的想法,更多的是屬于營(yíng)銷(xiāo)上東西。他說(shuō),實(shí)際上,“我們并不認為我們能夠交付所有這一切,基本上,我們辦不到”。這就是這種語(yǔ)言的發(fā)明者所說(shuō)的,并不存在什么純粹性和可移植性。
Osborn:
我們有沒(méi)有遺漏一些沒(méi)透露的C#的偉大的特性或創(chuàng )新,你愿意補充一下嗎?
Hejlsberg:
關(guān)于整個(gè).NET框架,隱含地,也包括C#,我想提的一點(diǎn)是:它是構建分布式應用的手段。并非很久以前,我們創(chuàng )建兩階層的客戶(hù)機/服務(wù)器應用,然后對象協(xié)議如CORBA、IIOP、RMI和DCOM接踵而至。這種類(lèi)型的編程是EJB(以CORBA或RMI為基礎而實(shí)現)的基礎。我們已經(jīng)會(huì )構建這種強連接式的分布式系統,但它們不具備伸縮性。它們在WEB上不能夠伸縮因為它們是有狀態(tài)的,它們在服務(wù)端保持狀態(tài),你不能夠轉入另一臺機器,把它插入并讓相關(guān)東西復制自己。
當初,當我們坐下來(lái)著(zhù)手設計.NET框架時(shí),我們回頭看了看Web上究竟發(fā)生些了什么。它正在變成松散連接、非常分布式的世界。我們努力理解它對潛在的編程模型的影響。因此,我們從根本上假定分布式應用是以松散連接、無(wú)狀態(tài)風(fēng)格構建的,我們做出的設計可提供巨大的伸縮性,你只管擴展。你轉入更多的框架并把它們插入。一旦做出了這個(gè)根本性的假設,一切就隨之改變。它改變了怎樣設計你的基本服務(wù),怎樣設計你的消息技術(shù),甚至怎樣設計你的用戶(hù)界面。這是一個(gè)新的編程模型。我們已經(jīng)決定使用XML和SOAP作為使這個(gè)模型工作的方式。它們被深深地集成進(jìn).Net,并且這種集成對于我們在設計.NET框架時(shí)做出的每一個(gè)決策是如此核心,以至于它不是那種你只進(jìn)來(lái)蜻蜓點(diǎn)水地逛一逛就可以的東西。
Osborn:
你能指出一些對程序員來(lái)說(shuō)明顯特別的地方嗎?
Hejlsberg:
一個(gè)相當好的例子是XML是如何被集成到C#中的。C#中有特性(attribute)的概念,它允許你向類(lèi)型和成員加入宣告性的信息。就象你可以說(shuō)某個(gè)成員是公用的或私用的一樣,你可能還想說(shuō)這個(gè)是事務(wù)的,或者這個(gè)假定是個(gè)Web service,或者這個(gè)假定可以序列化為XML。因此,我們加入特性以提供一般性機制,但我們在所有Web service和XML基礎設施中都用到了它。我們還給你用特性修飾類(lèi)和字段的能力。在你的類(lèi)中,你可以說(shuō)“當這個(gè)類(lèi)變成XML時(shí),它應該變成“this”標簽名,并且屬于“this”XML名字空間?!蹦銓⒛軌蛑付ㄒ粋€(gè)字段變成一個(gè)元素,而另外一個(gè)變成一個(gè)屬性(譯注:attribute,此處指XML中的屬性)。你還能夠控制XML的模式(譯注:即schema);在你的聲明類(lèi)的地方控制它,這樣,所有附加的宣告性的信息就都有了。一旦以該方式正確地使用特性修飾你的C#代碼,系統就可以簡(jiǎn)單地把一個(gè)特定的類(lèi)轉化成XML,在線(xiàn)上傳輸,當它傳回時(shí),就可以在另一端重建該對象。這都是在一處定義完成的。它不象傳統的定義文件或雜七雜八的信息和命名模式,它就在那兒。當你在IDE中創(chuàng )建它們時(shí),它就給了你完整的聲明。我們還可以提供更高級的工具,讓它幫你做這個(gè)事。
我知道我有點(diǎn)離題了,但我們提供的這些基礎設施的確令人興奮。單單因為我們有這些特性,你就可以請求XML序列化基礎設施或Web service基礎設施把已給出的類(lèi)轉換成XML。當你這樣做時(shí),我們實(shí)際上將為這個(gè)類(lèi)配上XSD schema,并且,我們將創(chuàng )建一個(gè)專(zhuān)門(mén)化的解析器,它是從我們一般的XML解析器(它是.NET基類(lèi)的一部分)派生下來(lái)的,并且覆寫(xiě)方法,并向解析器加入邏輯,因此它是專(zhuān)門(mén)為那個(gè)模式服務(wù)的。我們已經(jīng)實(shí)體化好一個(gè)解析器,可以本地代碼的速度解析XML。如果它不正確,我們將給你一個(gè)體面的出錯信息,它可以精確地告訴你是什么出了問(wèn)題。我們可以在代碼緩存基礎設施中緩存它,它將坐等直到下一次一個(gè)具有同樣模式的類(lèi)來(lái)臨并將發(fā)生作用,“嘭!”,我的意思是,難以置信,難以置信的處理能力!
Osborn:
所以,下面的確有許多有意思的引擎...
Hejlsberg:
Yeah。我認為,對于在這個(gè)領(lǐng)域里達成此種思想,我們是領(lǐng)先的一代。
Osborn:
精彩之至。謝謝,耽誤你時(shí)間了。
Hejlsberg:
不客氣。
聯(lián)系客服