Dylan語言

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

**概述**
在Dylan參考手冊中有簡明而徹底的語言概述。Dylan派生自Scheme和Common 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 TR1），幷包括了一個高級集成開發環境（IDE）。
其他兩個小組對語言設計和開發實現做出了貢獻：Harlequin公司發行了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參考手冊中有詳盡描述。

**詞法**
Dylan不是大小寫敏感的。Dylan的詞法允許使用連字暨減號的命名約定，來連接多單詞標識符的各部份（有時叫做“lisp-case”或“kebab case”）。這個約定在Lisp語言中是常見的，但不適用於將不是數值文字一部份的連字號暨減號，當作一個單一詞法記號處理的那些編程語言，即使在它沒有包圍著空白字符的時候。
除了字母數字字符和連字暨減號之外，Dylan允許特定非字母數字字符作為標識符的一部份。標識符不可以單獨的由非字母數字字符或數字字符組成。如果有任何歧義，應使用空白。

**樣例代碼**
有幾個槽的一個簡單的類：
define class  ()
slot point-x :: ,
required-init-keyword: x:;
slot point-y :: ,
required-init-keyword: y:;
end class ;
在約定上，類使用尖括號（即小於號和大於號）來命名，比如這個代碼例子中的類名字。
在end class 中，class和二者都是可選的。對所有end子句都是如此。例如，可以寫end if或只寫end來終止一個if語句。
同樣的類，可以用極小化方式重寫為：
define class  ()
slot point-x;
slot point-y;
end;
槽現在都確定類型為。槽必須被手動初始化。
在約定上，常量名字開始於$：
define constant $pi ::  = 3.1415927d0;
階乘函數：
define method factorial (n :: ) => (n! :: )
case
n  error("Can't take factorial of negative integer: %d\n", n);
n = 0     => 1;
otherwise => n * factorial(n - 1);
end
end;
這裡的n!和就是正常的標識符。
這裡沒有顯式的返回語句。一個方法或函數的結果是最後求值的那個表達式。除掉在返回位置上的表達式後面的分號是常見的風格。

**模塊與命名空間**
在很多面向對象語言中，類是封裝和模塊化的主要方式；每個類定義一個名字空間並控制哪些定義是在外部可見的。進一步的，在很多語言中類定義必須被用作一個整體的不可見單元。例如，使用String串接函數要求導入並編譯全部的String。
某些語言包括Dylan，還包括一個分立的顯式的命名空間或模塊系統，可以用更一般性的方式進行封裝。
在Dylan中，編譯單元和導入單元的概念是分開的，類對於二者都沒有什麼特殊可以言。“庫”定義應當被一起編譯和處理的項目，而“模塊”定義一個命名空間。類可以一起放置在模塊中，或分拆至其中，隨編程者意願。經常是一個類的完全定義不存在於一個單一的模塊中，而是延展於進行選擇性收集的多個模塊至上。不同的程序可以有相同的類的不同的定義，並只包括它們所需要的。
例如，考慮支持String的一個附加庫regex。在某些語言中，一個功能要被包括在字符串中，這個功能就必須被增加到String命名空間。隨著這種事情不斷髮生，String類變得越來越大，而不需要使用regex的函數仍必須為增加了庫大小付出代價。為此，這種附加件典型的放置在它們自己的命名空間和對象之中。這種方式的缺點是新函數不再是String的一部份；它轉而被隔離在單獨聲明的它自己的函數集合之中。不再使用myString.parseWith(myPattern)，從OO視角這是自然的組織方式，而是使用像 myPattern.parseString(myString)這樣的東西，它在效果上反轉了次序。
在Dylan之下，可以為相同代碼定義很多接口，例如String串接方法可以給放置在String接口和concat接口二者之中，後者將不同的類中的不同的串接函數收集在一起。這常用於數學庫中，這裡的函數意圖適用於廣泛的不同對象類型。
接口構造的更實際用法是建造一個模塊的公開和私有版本，在其他語言中這被包括為一個附帶特徵，並總是導致問題並增加語法。在Dylan之下，所有的函數調用可以簡單的放置在“私有”或“開發”接口中，而把可公開訪問的函數收集在Public接口之中。在Java或C++之下，一個對象的可見性是定義在代碼中的，意味著要提供類似的變更，編程者將被強制的去完全重寫定義，並且不能同時有兩個版本。

**類**
在Dylan中以類似於大多數OO語言的風格，類描述了對象的slot（槽，數據成員，字段，ivar等）。 所有對槽的訪問都要通過方法，就像Smalltalk那樣。缺省的getter和setter方法基於槽名字而自動生成。對比於多數其他OO語言，可應用於類的其他方法經常定義於這個類的外部，因此在Dylan中類定義典型的只包括存儲的定義。例如：
define class  ()
slot title ::  = "untitled", init-keyword: title:;
slot position :: , required-init-keyword: position:;
end class;
在這個例子中，定義了類。語法只是約定，使得類名字顯得突出，尖括號只是這個類名字的一部份。與之相對比，在一些語言中，約定為大寫類名字的首字母，或給名字前綴上C或T（舉個例子）。繼承了一個單一類，幷包含二個槽：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語言一樣。但是代碼實際上位於泛化函數之中，意味著它們不附屬於特定的類，並可以被任何人自然的調用。下例將類的方法turn-blue併入同名的泛化函數之內：
define method turn-blue (w :: )
w.color := $blue;
end method;
這個定義類似於其他語言的定義，並有可能被封裝到類之中。注意:=這個setter調用，它是color-setter($blue, w)的語法糖。
泛化函數的自主利用可見於更泛化的例子之中。例如，在多數語言中的一個常見函數to-string，它返回這個對象的某種人類可讀形式。比如說一個窗口可能返回它的標題和它在父窗口中的位置，而一個字符串將返回它自身。在Dylan中，這些方法可以給收集到叫作to-string的一個單一模塊中，因而這個代碼被從這個類自身的定義中移除。如果一個特定對象不支持to-string，可以簡單的在to-string模塊中增加上它。

**擴展性**
上述的整體概念可能讓讀者覺得很奇怪。處理一個窗口的to-string不定義在之中。除非考慮到Dylan對to-string調用的處理方式，否則就可能變得沒有意義。在多數語言中，在程序編譯的時候，查找給的to-string並把它替代為到這個方法的一個指針（或多或少）。在Dylan中，這發生在程序初次運行的時候，運行時系統建造一個方法名字/形式參數細節的表格，並通過這個表格來動態的查找方法。這意味著一個特定方法可以位於任何地方，不只是在編譯時間單元中。最後編程者得到了在放置其代碼上的相當大的靈活性，只要合適，可以收集在它的類之中，也可以與相同功能的方法收集在泛化函數中。
這裡隱含著編程者可以通過在單獨文件中定義函數，來向現存的類增加功能。例如人們可能希望向所有增加拼寫檢查，這在多數語言中將需要訪問到字符串類的源代碼，而這種基本類很少以源代碼形式給出。在Dylan（和其他可擴展語言）中，拼寫檢查方法可以增加到spell-check模塊中，通過define method構造定義它可以適用的所有的類。在這種情況下，實際功能可以定義在一個單一的泛化函數中，它接受一個字符串並返回錯誤。當spell-check模塊被編譯入程序的時候，所有字符串（和其他對象）都會得到這個增加的功能。

**引用**

**外部鏈接**
opendylan.org, Open Dylan – hosts open source, optimizing Dylan compiler targeting Unix/Linux, macOS, Microsoft Windows- Overview of the language date=20201031071858 - An Introduction to Dylan date=20210120132722 - Apple Dylan TR1- The Marlais Dylan Interpreter date=20181106064414  – An implementation of a subset of Dylan, suitable for bootstrapping a compiler
*Dylan