一次公司内部的Tech Talk中涉及到的关于语言的发展问题
C#從一開始就是強類型語言,直到現在都堅持早綁定。對于晚綁定,C#只是一種選擇,可能以不同于VB的方式來做而且會有所改進。對于老式的弱類型對象模型來說,比如OLE,如果從晚綁定角度出發,會比從早綁定好討論,因為這種對象模型無非就是對象若干方法的交互。
?????? 當你查看一個大函數內部嵌套很深的結構,比如FOR循環時,語言是何時,如何處理變量捕獲、如何進行實例保護就非常不同。在C#中,每次循環時實例都被保護,而VB有點像JavaScript,變量被隱性提升到函數頂部。所以,在變量捕獲方面也存在語義上的區別。有時這些區別及其細微,必須用非常變態的程序才能觀察到。
?????? LINQ, 函數型語言風格,所有的東西都基于表達式。“表達式”從其定義來說就是可組合的。不斷提高程序員的生產率:提升抽象的層次——垃圾回收機制,類型安全,異 常處理,全新的“聲明型”編程語言等。聲明型語言獲得了更高層次的“可組合性”。當我們更多的使用“函數型”或者“聲明型”風格的編程時,更有可能把運行 時框架構建得能更好的發揮多核的優勢,更好的處理并發。如果以“命令型”風格來工作,能發揮的余地就很小,因為無法預見所有動作,必須串行執行否則不可預 料。
?????? CLR以 及目前絕大多數的運行時都是“命令型”引擎,指令都相當傳統,比如堆棧增長;它們擁有易變的狀態,包括易變的全局狀態等等。在此之上,之所以能進行“函數 型”編程,是因為“函數型”編程本質上是“命令型”編程所具備的能力集的一個子集。最大化這種靈活性,使“函數型”能力子集越來越相關和主流化。
???? “函數型”語言是“串行執行”的好藥方。要想使“函數型”語言運轉良好,關鍵點并不是處理好基本的表達式問題,而是處理好lambda表達式和副作用的問題,使能夠將表達式作為第一級的編程要素來使用,能夠指出lambda表達式和Closure(函數型編程語言中的概念,可以方便組合函數,返回函數)的副作用。
??? “動態類型”和“隱式類型”的區別:一種情況是,靠編譯器推斷出類型,但編譯器在編譯期就推斷出來了。另一種情況是,編譯器在編譯時一無所知,它假設是任何類型,然后在運行時的適當時機,檢查到底是什么類型。因為在默認情況下推斷本地變量聲明的類型,所以無論 Option Strict 的設置為何,總是早期綁定對于這些變量的訪問。在 Visual Basic 9.0 中,程序員必須按以下方式將變量顯式聲明為類型 Object,從而顯式指定晚期綁定:要求使用顯式晚期綁定是為了防止意外使用晚期綁定,但更重要的是,這樣做可以有力地擴展它對諸如 XML 等新數據類型的晚期綁定。
?????? 新的 Visual Basic 9.0 對象初始值設定項 采用的是一種基于表達式的 With 格式,用于以簡明的方式創建復雜的對象實例。通過對象初始值設定項,我們能夠將以上兩條語句捕獲為一條(隱式類型的)本地聲明。這種在表達式中進行的對象初始化對于查詢而言非常重要。一條查詢語句通常就像由等號右側的 Select 子句初始化的對象聲明。由于 Select 子句返回一個表達式,因此我們必須能夠以一條表達式初始化整個對象。任何支持 Add 方法的集合都能夠通過一個集合初始值設定項 表達式進行初始化。
動態語言今年來發展很快,各種腳本語言多少都帶有些動態語言的特點。動態語言以其靈活的語法和豐富的運行時行為贏得了許多人的青睞。在.NET陣營,C#一直扮演著靜態語言的角色,盡管3.0的語法改變很激進,但仍注重于編譯時的類型檢查和約束。動態特性用的不好會產生更多運行時問題,不易確保程序的可靠性,但其提高開發效率的作用是毋庸置疑的。Visual Basic 9.0是Visual Studio中唯一能讓你統領動態和靜態兩大領域的語言,讓你在程序中自由選擇喜歡的風格。
注意在:=符號之前的大括號,表示對參數名稱的動態結合。有了動態標識符這一特性,Visual Basic 9.0將不需要利用反射的復雜語法,就可以做很多需要反射和運行時類型信息來做的任務,這使得Visual Basic成為解決你手邊小問題的最佳幫手。
?????? 在隱式類型的局部變量聲明中,局部變量的類型是通過局部聲明語句右側的初始值設定項表達式推斷的。推斷類型可防止意外使用后期綁定,更重要的是,它允許為新數據類型(如 XML)綁定強大擴展。局部變量類型推測:不要擔心性能問題;它是編譯時由編譯器進行推測的,是一種強類型的特性。 同時,VB 9還支持For(For Each)的循環變量推測,無需再臨時定義循環變量。
?????? 后期綁定:若將一個變量聲明為 As Object 或 As Variant(包括 As Form 或 As Control 的變量),Visual Basic 在編譯時就無法確定該變量將引用哪種類型的對象。因而,Visual Basic 必需使用后期綁定,在運行時確定對象的屬性和方法能否使用該變量。
?????? 若使用后期綁定,則每次調用屬性或方法時,Visual Basic 都要將成員名傳給該對象 IDispatch 接口的 GetIDsOfNames 方法。GetIDsOfNames 返回該成員的派遣 ID,或 DispID。Visual Basic 再將該 DispID 傳給 IDispatch 接口的 Invoke 方法來調用該成員。
?????? 前期綁定:要是在編譯時 Visual Basic 能夠知道屬性或方法所屬的對象,就可以預先查找該成員在類型庫中的 DispID 或 vtable 地址。這樣就無須在運行時調用 GetIDsOfNames。
?????? 當顯式聲明了變量的類時,例如 As Widget,該變量就只能存放該類的對象的引用。Visual Basic 就可認為該變量調用的所有屬性和方法使用前期綁定。
?????? 建議在 Visual Basic 和應用程序中使用這種方法來聲明對象變量。
?????? 使用前期綁定還是后期綁定完全取決于聲明變量的方式。對象的樹立方式對此沒有任何影響。
?????? 后期綁定的幾個優勢和好處
第一,個人以為,由于VB6不支持實現繼承,對于某些設計,可以使用將對象定義為Variant變量,而獲取某些設計和編碼上的便利,而得到接口或抽象類的好處。這樣,無須繼承機制,也可以得到抽象接口的優勢,而使接口、實現分離。
第二,在調用外部的COM自動化組件時,如Office,要是通過這種方式調用,對于不同版本的Office,要是你調用的方法、屬性都是存在的,那么可以適應不同版本的Office,但要是通過前期綁定,在項目引用中確定對象類型,是有版本兼容問題的。
效率和劣勢
?????? 其實最主要的劣勢是效率問題,《Advanced Visual Basic 6》一書說,使用Variant變量和Long變量進行循環,效率差別是1.5倍,而沒有他人以為的那么大,而且對于大對象,差異也不是很大。對于本文前邊的例子,要是建立的是進程內對象,前期綁定和后期綁定調用效率區別大概2:3左右,也就是說也是1.5倍。對于調用Office這樣的外部COM自動化對象,也許區別大一些,沒有專門測試,不過對于Office自動化,速度主如果決定于Office本身的啟動、初始化。
?????? 另外一個劣勢是沒有了IDE下的屬性、方法成員自動列出。
?????? 早期綁定聯系由編譯器在根據.NET源 代碼創建程序集的期間創建。我們無法為一個虛方法或抽象方法創建一個早期綁定。事實上,當一個虛方法或抽象方法被調用時,多態機制會在執行期間根據被調用 方法的實際對象確定將要執行的代碼。這種情況下,該聯系被視為動態綁定。在其他資料中,動態綁定有時被稱為隱式的后期綁定,因為它們是由多態機制隱式創建 的并且是在執行期完成的。
?????? 現在讓我們進一步觀察早期綁定,它們是為靜態方法或類中那些不是虛方法或抽象方法的方法創建的。如果嚴格遵循前一節中對“類的聯系”的定義,.NET中是不存在早期綁定的。事實上,我們必須先等待JIT編譯器將方法體轉換為機器語言,才能知道它在進程地址空間中的物理地址。創建程序集的編譯器并不知道這個方法的地址信息[1]。為了解決這個問題,創建程序集的編譯器在IL代碼中方法將被調用的位置插入了與被調用的方法相對應的元數據符號(metadata token) 。當方法體被即時(JIT)編譯的時候,CLR在內部保存了方法與機器語言下的方法體的物理地址的對應聯系。這段被稱為存根的信息被物理保存到一個與方法相關的內存地址中。
?????? 以上的認識很重要,因為在像C++這樣的語言中,當一個方法不是虛方法或抽象方法(即C++中的純虛函數)時,編譯器就可以計算出該方法體在機器語言下的物理地址。然后,編譯器在每個調用該方法的位置插入一個指向該內存地址的指針。這個區別給了.NET很大的優勢,因為編譯器不需要再考慮諸如內存表現之類的技術細節。IL代碼完全獨立于它所運行的物理層。
?????? 而在動態綁定中,其中幾乎所有的事物都是以與早期綁定中相同的方式工作的。編譯器在IL代碼中方法被調用的位置插入了與被調用的虛(或抽象)方法相對應的元數據符號。這里,我們提到的元數據符號是屬于定義在引用類型中的方法的,而該引用類型就是將發生方法調用的那個類型。然后就是CLR的工作,它將在執行期間根據引用對象的具體實現確定跳轉到哪個方法。
?????? 最常見的原因在于某些語言根本就沒有編譯器!在一個腳本語言中,指令是被一條一條解釋的。在這種情況下,只存在后期綁定。通過使用后期綁定,可以使用由解釋型語言編譯的程序集中的類。在.NET中可以方便地使用后期綁定技術這一事實,使得創建一個專有的解釋/動態語言變得相對容易(比如IronPython語言http://www.ironpython.com/)。
我們可能希望在由編譯型語言如C#寫成的程序中使用后期綁定技術。原因在于,使用后期綁定可以為應用程序的通用架構帶來某種程度的靈活性。該技術實際上是一種最近很流行的被稱為插件的設計模式,我們將在本章對它做進一步介紹。
如果在程序集A編譯期間程序集B尚不存在,我們就必須在A中的代碼與B中的類之間使用后期綁定。這種情況我們將在稍后談到動態構造程序集的時候介紹。
?????? 一些人喜歡使用后期綁定來代替多態。事實上,因為在調用期間,只考慮方法的名稱與簽名式,而與被調用方法所處對象的類型無關,所以只需要在實現對象的時候提 供具有合適名稱和簽名式的方法即可。但是,我個人不推薦這種做法,因為它的約束性太差,并且無法促使應用程序的開發者去做恰當的設計以及使用抽象接口。
轉載于:https://www.cnblogs.com/brunoyu/archive/2009/07/18/1526124.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的一次公司内部的Tech Talk中涉及到的关于语言的发展问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何:修改 Office Open XM
- 下一篇: OXite解读(1)----- 概述