Dylan語言

Dylan是多範式的程式語言,包括了支援函數式物件導向程式設計(OOP),它是動態反射式的,卻提供了設計用於支援生成高效機械碼的編程模型,包括了在動態和靜態行為上的細粒度的控制。它是在1990年代早期由蘋果公司領導的群組創造的。

Dylan
編程範型多範式: 函數式, 物件導向, 多分派
語言家族Lisp
實作者蘋果公司, Harlequin英語Harlequin (software company), 卡內基·梅隆大學
釋出時間1992年4月,​32年前​(1992-04
目前版本
  • 2022.1(2022年11月28日)[1]
編輯維基數據連結
型態系統強型別, 動態
系統平台IA-32, x86-64
作業系統跨平台
副檔名dylan
網站opendylan.org
主要實作產品
Open Dylan, Gwydion Dylan
衍生副語言
中綴dylan, 字首dylan
啟發語言
CLOS, ALGOL, Scheme, EuLisp英語EuLisp
影響語言
Lasso英語Lasso (programming language), Python, Ruby, Julia[2]

概述

在Dylan參考手冊中有簡明而徹底的語言概述[3]。Dylan衍生自SchemeCommon Lisp,並增加了衍生自Common Lisp對象系統(CLOS)的整合的對象系統。在Dylan中,所有的值(包括數值、字元、函數和)都是頭等對象。Dylan支援多重繼承多型多分派關鍵字參數英語Named parameter、對象內省、基於模式語法擴充宏和很多其他進階特徵。程式可以表達在動態性上的細粒度的控制,允許程式佔據在動態和靜態編程之間的連續區,並支援演進式開發(允許先快速原型隨後增進精製和最佳化)。

Dylan的主要設計目標是成為適合開發商業軟件的動態語言。Dylan嘗試解決潛在的效能問題,通過向完全靈活性的Lisp系統介入「本性」限制,允許編譯器清晰的理解可編譯單元比如函式庫。Dylan從Scheme和其他Lisp衍生出了它的很多語意;某些Dylan實現最初建造在現存Lisp系統之內。但是Dylan有着類似ALGOL的語法而非類似Lisp的字首語法。

歷史

Dylan是在1990年代早期由蘋果公司領導的一個群組建立的。在它開發的時候,它被意圖用於Apple Newton電腦,但是Dylan實現那時還沒有達到充分成熟,而Newton轉而使用了C和Walter Smith開發的NewtonScript二者的混合。Apple在1995年終止了其Dylan開發努力,儘管他們製作了一個可獲得的「技術發行」版本(Apple Dylan英語Apple Dylan TR1),並包括了一個進階整合式開發環境(IDE)。

其他兩個小組對語言設計和開發實現做出了貢獻:Harlequin公司英語Harlequin (software company)發行了Microsoft Windows下的商業IDE,卡內基·梅隆大學發行了叫作Gwydion Dylan的Unix下的編譯器。二者的實現分別於2004年和1998年開放了原始碼。Harlequin實現當前叫作Open Dylan並由一組志願者維護。

Dylan語言的代號是Ralph。James Joaquin選擇名字Dylan表示「動態語言」(Dynamic language)。

語法

Dylan的多數語法特徵來自它的Lisp傳承。Dylan最初使用類似Lisp的字首語法,它基於了S-表達式。到了語言設計完成的時候,語法被變更為類似ALGOL的語法,預期廣泛的編程者受眾會更加熟悉它。語法由Michael Kahl設計。它在Dylan參考手冊中有詳盡描述[3]

詞法

Dylan不是大小寫敏感的。Dylan的詞法允許使用連字暨減號的命名約定,來連接多單詞識別碼的各部份(有時叫做「lisp-case」或「kebab case」)。這個約定在Lisp語言中是常見的,但不適用於將不是數值文字英語Literal (computer programming)一部份的連字號暨減號,當作一個單一詞法記號處理的那些程式語言,即使在它沒有包圍着空白字元的時候。

除了字母數字字元和連字暨減號之外,Dylan允許特定非字母數字字元作為識別碼的一部份。識別碼不可以單獨的由非字母數字字元或數字字元組成[3]。如果有任何歧義,應使用空白。

樣例代碼

有幾個槽的一個簡單的類:

define class <point> (<object>)
  slot point-x :: <integer>,
    required-init-keyword: x:;
  slot point-y :: <integer>,
    required-init-keyword: y:;
end class <point>;

在約定上,類使用尖括號(即小於號和大於號)來命名,比如這個代碼例子中的類名字<point>

end class <point>中,class<point>二者都是可選的。對所有end子句都是如此。例如,可以寫end if或唯寫end來終止一個if陳述式。

同樣的類,可以用極小化方式重寫為:

define class <point> (<object>)
  slot point-x;
  slot point-y;
end;

槽現在都確定類型為<object>。槽必須被手動初始化。

在約定上,常數名字開始於$

define constant $pi :: <double-float> = 3.1415927d0;

階乘函數:

define method factorial (n :: <integer>) => (n! :: <integer>)
  case
    n < 0     => error("Can't take factorial of negative integer: %d\n", n);
    n = 0     => 1;
    otherwise => n * factorial(n - 1);
  end
end;

這裏的n!<integer>就是正常的識別碼。

這裏沒有顯式的返回陳述式。一個方法或函數的結果是最後求值的那個表達式。除掉在返回位置上的表達式後面的分號是常見的風格。

模組與命名空間

在很多物件導向語言中,類是封裝和模組化的主要方式;每個類別定義一個名字空間並控制哪些定義是在外部可見的。進一步的,在很多語言中類別定義必須被用作一個整體的不可見單元。例如,使用String串接函數要求匯入並編譯全部的String

某些語言套件括Dylan,還包括一個分立的顯式的命名空間或模組系統,可以用更一般性的方式進行封裝。

在Dylan中,編譯單元和匯入單元的概念是分開的,類對於二者都沒有什麼特殊可以言。「庫」定義應當被一起編譯和處理的專案,而「模組」定義一個命名空間。類可以一起放置在模組中,或分拆至其中,隨編程者意願。經常是一個類的完全定義不存在於一個單一的模組中,而是延展於進行選擇性收集的多個模組至上。不同的程式可以有相同的類的不同的定義,並只包括它們所需要的。

例如,考慮支援String的一個附加庫regex。在某些語言中,一個功能要被包括在字串中,這個功能就必須被增加到String命名空間。隨着這種事情不斷發生,String類變得越來越大,而不需要使用regex的函數仍必須為增加了庫大小付出代價。為此,這種附加件典型的放置在它們自己的命名空間和對象之中。這種方式的缺點是新函數不再是String的一部份;它轉而被隔離在單獨聲明的它自己的函數集合之中。不再使用myString.parseWith(myPattern),從OO視角這是自然的組織方式,而是使用像 myPattern.parseString(myString)這樣的東西,它在效果上反轉了次序。

在Dylan之下,可以為相同代碼定義很多介面,例如String串接方法可以給放置在String介面和concat介面二者之中,後者將不同的類中的不同的串接函數收集在一起。這常用於數學庫中,這裏的函數意圖適用於廣泛的不同對象類型。

介面構造的更實際用法是建造一個模組的公開和私有版本,在其他語言中這被包括為一個附帶特徵,並總是導致問題並增加語法。在Dylan之下,所有的函數呼叫可以簡單的放置在「私有」或「開發」介面中,而把可公開訪問的函數收集在Public介面之中。在JavaC++之下,一個對象的可見性是定義在代碼中的,意味着要提供類似的變更,編程者將被強制的去完全重寫定義,並且不能同時有兩個版本。

在Dylan中以類似於大多數OO語言的風格,類描述了對象的slot(槽,數據成員,欄位,ivar等)。 所有對槽的訪問都要通過方法,就像Smalltalk那樣。預設的gettersetter方法基於槽名字而自動生成。對比於多數其他OO語言,可應用於類的其他方法經常定義於這個類的外部,因此在Dylan中類別定義典型的只包括儲存的定義。例如:

define class <window> (<view>)
  slot title :: <string> = "untitled", init-keyword: title:;
  slot position :: <point>, required-init-keyword: position:;
end class;

在這個例子中,定義了類<window><类名字>語法只是約定,使得類名字顯得突出,尖括號只是這個類名字的一部份。與之相對比,在一些語言中,約定為大寫類名字的首字母,或給名字字首上C或T(舉個例子)。<window>繼承了一個單一類<view>,並包含二個槽:title持有這個窗口標題的字串,和position持有這個窗口一角的X-Y點。在這個例子中,標題給出為預設值,而位置還沒有值。可選的init-keyword語法允許編程者在初始化這個類的對象時指定這個槽的初始值。

在語言比如C++或Java中,類還定義了它的介面。所以在這二種語言中,如果像上述案例中,類別定義沒有顯式的對可見性的指令,則對數據成員和方法的訪問都被當作是protected,意味着它們只能被子類使用。要使得無關代碼使用這個窗口的實例,它們必須給聲明為public

在Dylan中,這些槽的可見性規則不被當作這個代碼的一部份,而是模組/介面系統的一部份。這增加了相當大的靈活性。例如,在早期開發中用的介面可以聲明所有東西為public,而用在測試和部署中用的介面會加以限制。對於C++或Java,這種變更會需要改變原始碼,所有人們就不做了,而在Dylan中,這是完全無關的概念。

儘管這個例子沒有用到,Dylan還支援多重繼承

方法和泛化函數

在Dylan中,方法不是原生的關聯於任何特定的類;方法可以被認為存在於這個類之外。就像CLOS,Dylan是基於多分派(多方法)的,這裏特定方法的呼叫是基於它的所有實際參數的類型來選擇的。方法不需要在編譯時間就知道,基於用戶的偏好,所要求的函數可以是能獲得到的也可以不能。

在Java之下,相同的方法被隔離在特定的類之中。要使用這個功能,編程者被強制去import這個類並顯式的參照它來呼叫這個方法。如果這個類不可獲得,或在編譯時間未知,這個應用簡單的不能編譯。

在Dylan中,泛化函數表示零或多個類似的方法,用define method方式建立的所有方法自動的包含在同名的泛化函數之內。泛化函數也可以顯式的用define generic聲明,允許編程者精確控制可以增加哪種方法。代碼被隔離於儲存而位於泛化函數中。很多類在其中擁有它們自己的方法,因此在感官上就像多數其他OO語言一樣。但是代碼實際上位於泛化函數之中,意味着它們不附屬於特定的類,並可以被任何人自然的呼叫。下例將類<window>的方法turn-blue併入同名的泛化函數之內:

define method turn-blue (w :: <window>)
  w.color := $blue;
end method;

這個定義類似於其他語言的定義,並有可能被封裝到<window>類之中。注意:=這個setter呼叫,它是color-setter($blue, w)語法糖

泛化函數的自主利用可見於更泛化的例子之中。例如,在多數語言中的一個常見函數to-string,它返回這個對象的某種人類可讀形式。比如說一個窗口可能返回它的標題和它在父窗口中的位置,而一個字串將返回它自身。在Dylan中,這些方法可以給收集到叫作to-string的一個單一模組中,因而這個代碼被從這個類自身的定義中移除。如果一個特定對象不支援to-string,可以簡單的在to-string模組中增加上它。

擴充性

上述的整體概念可能讓讀者覺得很奇怪。處理一個窗口的to-string不定義在<window>之中。除非考慮到Dylan對to-string呼叫的處理方式,否則就可能變得沒有意義。在多數語言中,在程式編譯的時候,尋找給<window>to-string並把它替代為到這個方法的一個指標(或多或少)。在Dylan中,這發生在程式初次執行的時候,執行時系統建造一個方法名字/形式參數細節的表格,並通過這個表格來動態的尋找方法。這意味着一個特定方法可以位於任何地方,不只是在編譯時間單元中。最後編程者得到了在放置其代碼上的相當大的靈活性,只要合適,可以收集在它的類之中,也可以與相同功能的方法收集在泛化函數中。

這裏隱含着編程者可以通過在單獨檔案中定義函數,來向現存的類增加功能。例如人們可能希望向所有<string>增加拼寫檢查,這在多數語言中將需要訪問到字串類的原始碼,而這種基本類很少以原始碼形式給出。在Dylan(和其他可延伸語言)中,拼寫檢查方法可以增加到spell-check模組中,通過define method構造定義它可以適用的所有的類。在這種情況下,實際功能可以定義在一個單一的泛化函數中,它接受一個字串並返回錯誤。當spell-check模組被編譯入程式的時候,所有字串(和其他對象)都會得到這個增加的功能。

參照

  1. ^ https://opendylan.org/news/2022/11/28/new-release.html.
  2. ^ Stokel-Walker, Chris. Julia: The Goldilocks language. Increment. Stripe. [23 August 2020]. (原始內容存檔於2020-11-09). 
  3. ^ 3.0 3.1 3.2 Andrew Shalit; David Moon; Orca Starbuck. The Dylan Reference Manual. Apple Press. Addison-Wesley. 11 September 1996 [2021-03-13]. ISBN 9780201442113. (原始內容存檔於2021-05-30). 

外部連結