Smalltalk 是一種動態型別、反射式的面向物件程式語言。Smalltalk 由艾倫凱、Dan Ingalls、Ted Kaehler、Adele Goldberg 等於 1970 年代在施樂帕羅奧多研究中心開始開發。 Smalltalk 對其它眾多的程式設計語言的產生起到了極大的推動作用，特別是 ObjectiveC、CLOS、Python 和 Ruby 等。1990 年代湧現的許多軟體開發思想都得益於 Smalltalk，例如設計模式、敏捷程式設計和程式碼重構等。 概述 Smalltalk 和許多程式設計語言不同，它不僅僅是一門語言。下面從幾個不同的角度來解釋 Smalltalk。 一種面向物件的程式設計語言：它是一種面向物件的語言，包含語言的語法和語義。一些編譯器可以透過 Smalltalk 源程式產生可執行檔案。這些編譯器通常產生一種能在虛擬機器上執行的二進位制程式碼。Smalltalk 語言本身非常精煉。 一種程式設計環境：這裡指的是一種提供許多 zhhans 物件；zhhant 物件； 的系統，而不是某種特殊的開發環境。和許多語言不同（包括 C），Smalltalk 附帶有一個巨大的、相當標準的類庫。這些類使得開發 Smalltalk 程式的效率非常高。在其它語言（例如 Ada、C 和 Pascal）中，通常被作為語言的一部分的功能（例如條件判斷，迴圈等），在 Smalltalk 由特定的類提供。 一個應用開發環境（ADE）：由於 Smalltalk 的歷史原因，它具有一個非常優秀的高度整合、開放的應用開發環境。由於開發環境中的瀏覽器、監視器以及偵錯程式，都由同樣的源程式衍生出來的，不同的版本之間也具有相當好的相容性。此外，這些工具的源程式都可以在 ADE 直接存取。 歷史 最早的 Smalltalk 原型由艾倫凱於 1970 年代初提出。類（來自 Simula 67）、海龜繪圖（來自 LOGO）以及圖形使用者介面（來自 Sketchpad 等先驅系統）等概念的有機組合，構成了 Smalltalk 的最初的藍圖。 在 1971 年到 1975 年之間，艾倫凱在 Xerox PARC 的小組，在 Xerox Alto 計算機上，設計並實現了第一個真正的 Smalltalk 語言系統，編譯器由 Dan Ingalls 負責主要實作。這個系統被稱為 Smalltalk71 與 Smalltalk72，具有以下幾個技術創新： 語言完全基於訊息交換和 Simula 67 的類的概念。 語言沒有固定的語法，語法分析由類本身完成。 開發環境的革新相當迅速。雖然當時的點陣圖顯示器十分昂貴，但是艾倫凱卻說服了 PARC，讓他使用這些點陣圖顯示器，這使得艾倫凱和他的小組，能夠實現不同大小和字型的文字，使用多視窗環境，以及一些對影像處理的高階支援。Smalltalk72 影響了演員模型的發展，它的語法和執行模型，與現代的 Smalltalk 變體有著顯著的差異。 在 1975 到 1976 年間，艾倫凱小組認識到應當對執行效率和規模進行最佳化。於是他們在許多重要方面重新設計了 Smalltalk 系統，被稱為 Smalltalk76，它在語言上： 引入了繼承和子類的概念。 確定了語言的語法，這使得編譯器能夠產生高效、可執行、精煉的二進位制程式碼。 拉里泰斯勒設計了類瀏覽器，這極大地提高了 Smalltalk 程式設計師的程式設計效率。 前述的所有 Smalltalk 系統，都是在特殊的硬體上實現的，直到 1977 年至 1978 年，Bruce Horn 和 Ted Kaehler 把 Smalltalk76 移植到上，它是由 Intel 8086 處理器和自定顯示器所組成的硬體環境。雖然這種硬體環境只生產了 10 臺，但是它證明了在通常的處理器上實現 Smalltalk 的可能性。 在 1979 至 1980 年，部分受 NoteTaker 專案的影響，Smalltalk 小組的注意力轉移到 Smalltalk 的銷售可行性上。小組設計並實現了新一代的 Smalltalk 系統，這次修改的目標著重於在標準硬體上的移植性等方面，被稱為 Smalltalk80，它包括： 採取 ASCII 碼字元集，摒棄了原先在 Smalltalk72 和 Smalltalk76 中使用的特殊字元。 取消了原始方法直接存取記憶體的能力。取而代之的是引入一系列的原始方法提供相應的功能。 引入了元類的概念。 引入 MVC（模型 檢視 控制器）系統以方便互動式應用軟體的開發。 Smalltalk80 是在 PARC 之外能獲得到的第一個語言變體，最初作為 Smalltalk80 版本 1，給與了少數公司（惠普、蘋果公司、泰克和 DEC）和大學（UC Berkeley），用於同行評審和在它們自己的平臺上實現。後來在 1983 年普遍可獲得的實現，叫做 Smalltalk80 版本 2，發行為虛擬機器規定和映像（具有物件定義的獨立於平臺的檔案）。 1988 年 Xerox PARC 為了將 Smalltalk 推向市場而成立了分拆公司 ParcPlace Systems。ANSI Smalltalk 自從 1998 年來是標準的語言參考。 兩個當前流行的 Smalltalk 實現變體，是這些最初 Smalltalk80 映像的後代。Squeak 是開源實現，它經由 Apple Smalltalk，派生自 Smalltalk80 版本 103。經由 Smalltalk80 25 和 ObjectWorks（二者都是 ParcPlace Systems 的產品），派生自 Smalltalk80 版本 2。 面向物件程式設計 如同其他面嚮物件語言，Smalltalk80（而非 Smalltalk72）的中心概念是 物件 。一個物件總是一個 類 的一個 例項。類是描述它們的例項的屬性和行為的 藍圖。例如，一個 GUI 視窗類，可以宣告視窗擁有的屬性，比如標籤、位置和視窗是否可見。這個類還可以宣告其例項支援的操作，比如開啟、關閉、移動和隱藏。每個特定視窗物件，對這些屬性都有自己的值，它們每個都能進行它的類定義的操作。 Smalltalk 物件確切的可以做三件事： 持有狀態（引用到其他物件）。 接收訊息自本身或其他物件。 在處理一個訊息的過程中，傳送訊息至本身或其他物件。 一個物件持有的狀態總是私有於這個物件。其他物件只能透過發動請求（訊息）至這個物件，來讓它做出查詢或變更這個狀態。任何訊息可以傳送給任何物件：當接收到一個訊息的時候，接收者確定這個訊息是否合適。Alan Kay 評論說，儘管關注於物件，訊息才是 Smalltalk 中最重要的概念：最大的想法是訊息傳遞，它是 SmalltalkSqueak 核心的全部意義所在（它是我們在 Xerox PARC 階段從未真正完成的某種東西）。 不同於多數其他語言，Smalltalk 物件可以在系統執行的同時進行修改。現場編碼和飛速應用補丁，是 Smalltalk 的主導程式設計方法論，並且是它高效的主要原因。 Smalltalk 是 純 面向物件程式語言，這意味著，不像 C 和 Java，在作為物件的值和作為原始型別的值之間沒有區別。在 Smalltalk 中，原始值比如整數、布林值和字元，也是物件，這麼說的意義在於它們也是相應類的例項，而且要傳送訊息來呼叫在它們上的運算。程式設計者可以透過子類，改變或擴充套件實現原始值的類，使得可以向它們的例項定義新行為，例如實現一個新的控制結構，甚至使得它們現有行為得以改變。這個事實被總結成常聽到的一句短語：在 Smalltalk 中，所有東西都是物件，它可以更精確的表達為：所有的值都是物件，因為變數不是。 因為所有的值都是物件，類也是物件。每個類都是這個類的元類的一個例項。元類都是 Metaclass（元類類）的例項，它也是物件，並且是 Metaclass class（元類元類）的例項。程式碼塊是 Smalltalk 表達匿名函式的方式，它也是物件。 Hello World 例子 Hello World 程式，實質上被所有計算機語言的課本用作要學習的第一個程式，它展示了這個語言的最基本語法和環境。對於 Smalltalk，這個程式可極其簡單的書寫。下列程式碼中，訊息 show 被髮送給物件 Transcript，具有字串文字 Hello World 作為它的實際引數。呼叫 show 方法，導致它的實際引數，即字串文字 Hello World，顯示在叫做 副本（Transcript）的終端視窗： Transcript show Hello World 注意需要開啟 Transcript 視窗，來看到這個例子的結果。 語法 Smalltalk80 語法是相當極簡主義的，只基於了一小把的宣告和保留字。事實上，Smalltalk 中只保留了六個 關鍵字：true、false、nil、self、super 和 thisContext。它們的準確術語是 偽變數，是服從變數識別符號規則的識別符號，但指示了程式設計者所不能變更的繫結。true、false 和 nil 偽變數是單例例項。self 和 super，在響應一個訊息而啟用的方法中，指稱這個訊息的接收者；但是傳送給 super 的訊息，在這個方法的定義類的超類中查詢方法，而非這個接收者的類中，這允許子類中的方法呼叫在超類中的同名方法。thisContext 指稱當前的活動記錄。 內建的語言構造只有訊息傳送、賦值、方法返回和某些物件的文字語法。從它最初作為給所有年齡兒童的語言開始，標準的 Smalltalk 語法以更像英語，而非主流編碼語言的方式使用標點符號。語言餘下部份，包括用於條件求值和迭代的控制結構，都由標準 Smalltalk 類庫實現在內建構造之上。出於效能上的原因，實現可以識別並特殊處理某些這種訊息，但這只是最佳化而並未硬性規定入語言語法。 諺語 Smalltalk 語法適合一張明信片，所提及的是的一個程式碼片段，展示了一個方法的所有基本標準語法元素： exampleWithNumber x y true false not nil isNil ifFalse self halt y self size super size a a a 1 10 do each Transcript show each class name show each printString show x y 文字 下列例子詮釋了最常用的物件，可以在 Smalltalk80 方法中被寫為值。 數和字元 下列是數的某些可能例子： 42 42 12345 12345e2 2r10010010 16rA000 最後兩個專案分別是二進位制和十六進位制數。在 r 前的數是底數或基數。基數不必須是二的冪；例如 36rSMALLTALK 是一個有效的數值，等價於十進位制的 80738163270632。 字元書寫時帶有前導的美元符： A 字串 字串是包圍在單引號內的字元序列： Hello world 要在一個字串中包括一個引號，使用另一個引號來轉義： I said Hello world to them 雙引號不需要轉義，因為單引號界定字串： I said Hello world to them 兩個相等的字串（字串相等，如果它們包含完全相同的字元）可以是駐留在記憶體不同位置中的不同物件。 符號 除了字串，Smalltalk 有一類叫做（Symbol）的字元序列物件。符號保證是唯一的，沒有作為不同物件的兩個相等的符號。因此，符號非常易於比較，並經常用於語言構造中，比如用作訊息選擇子。 符號被寫為 跟隨著。比如： foo 如果一個序列不包含空白或標點字元，還可以寫為： foo 陣列 例如定義了四個整數的一個數組： 1 2 3 4 很多實現支援下列位元組陣列（ByteArray）的文字語法，例如定義了四個整數的位元組陣列： 1 2 3 4 其他 最後卻重要的是塊（匿名函式文字） 一些 smalltalk 程式碼 很多 Smalltalk 方言為其他物件實現了額外的語法，但是上述的是所有方言都本質上支援的。 變數宣告 在各種 Smalltalk 中共同使用的有兩種變數：例項變數和臨時變數。其他變數和有關術語依賴於特定實現，例如有類共享變數和名字空間共享變數，而 Squeak 和很多其他實現，有類變數、池變數和全域性變數。 在 Smalltalk 中臨時變數宣告是在方法（見後）內宣告的變數。它們宣告在方法的頂部，作為由豎槓包圍的空格分隔的名字。例如： index 宣告一個臨時變數名叫 index，可以包含初始值 nil。 多個變數可以在一組豎槓內宣告： index vowels 聲明瞭兩個變數：index 和 vowels。所有變數都要初始化。字串的索引變數，初始化為 null 字元或初始為 0 的 ByteArray，此外的所有變數初始化為 nil。 按命名約定，例項變數、臨時變數、方法或塊的引數，應當以小寫字母開頭，指示它們具有私有作用域，它們合稱為區域性變數。而全域性變數、類變數、池字典、類名字，應當以大寫字母開頭，它們合稱為共享變數。 賦值 變數透過 語法來指定一個值。比如： vowels aeiou 指定字串 aeiou 至前面宣告的 vowels 變數。這個字串是個物件（在單引號之間的字元序列是文字字串的語法），在編譯時間由編譯器建立。 在最初的 Parc Place 映像中，現在下劃線（_）的字形，在那時是左向箭頭字形（就像 1963 年版本 ASCII 程式碼中那樣）。Smalltalk 最初接受左向箭頭，作為唯一的賦值算符。一些現代程式碼仍然包含充當賦值的下劃線，會讓人想起這種最初的用法。多數現代的 Smalltalk 實現接受要麼下劃線，要麼冒號等號語法。 訊息 訊息是 Smalltalk 中最基礎的語言構造。所有控制結構都實現為訊息傳送。Smalltalk 預設的採用動態分派和單一分派策略，這是相對於其他一些面嚮物件語言使用的多分派而言的。 一元訊息 下列例子是傳送訊息 factorial 至數值 42： 42 factorial 在這種情況下，42 叫做這個訊息的 接收者，而 factorial 是訊息的選擇子。接收者透過返回一個值來相應這個訊息（這個情形中是 42 的階乘）。同其他事物一樣，訊息的結果可以賦值給一個變數： aRatherBigNumber 42 factorial 上面的 factorial 是 一元 訊息，因為只涉及了一個物件，即接收者。 關鍵字訊息 訊息可以承載額外的物件作為實際引數，比如： 2 raisedTo 4 在這個表示式中，涉及了兩個變數：2 作為接收者而 4 作為訊息的實際引數。訊息結果，或用 Smalltalk 的說法，回答被認定為 16。這種訊息叫做 關鍵字 訊息。訊息可以有多個實際引數，使用如下語法 hello world indexOf o startingAt 6 它的回答是在接收者字串中字元 o 的索引，從索引 6 開始查詢。這個訊息的選擇子是 indexOfstartingAt，構成自兩個部份或關鍵字。 這種關鍵字和實際引數的交織意圖改進程式碼的可讀性，因為實際引數由前導於它們的關鍵字來解釋。例如，要建立一個矩形的表示式使用 C 或 Java 類語法可以寫為： new Rectangle 100 200 不清楚這些實際引數分別是什麼。與之相反，在 Smalltalk 中，這個程式碼可以寫為： Rectangle width 100 height 200 這個情況下接收者是 Rectangle 類，回答是這個類的具有指定寬度和高度的一個例項。 二元訊息 最後，多數特殊（非字母）字元可以被用作所謂的 二元訊息。這些允許了數學和邏輯算符以傳統形式書寫： 3 4 它傳送訊息 給接收者 3，具有 4 作為實際引數傳遞（回答將是 7）。類似的： 3 4 將訊息 傳送給 3 具有實際引數 4（回答將是 false）。 注意，Smalltalk80 語言自身，不包含著這些算符的含義。上述的結果，都只是這些訊息的接收者（這裡是數值例項），為了響應訊息 和 而定義並返回的。這個機制的副作用是運算子過載，訊息 可以被其他物件所理解，允許使用形如 a b 的表示式來比較它們。 表示式 一元訊息可以一個接一個的寫成方法鏈式呼叫： 3 factorial factorial log 它傳送 factorial 到 3，接著傳送 factorial 到前面的結果 6，接著傳送 log 到前面的結果 720，產生最終的結果 285733。 一個表示式可以包括多次訊息傳送。在這個情況下，表示式依據一個簡單的優先順序次序來分析。一元訊息有最高的優先順序，隨後是二元訊息，最後是關鍵字訊息。例如： 3 factorial 4 factorial between 10 and 100 被求值如下： 3 接收訊息 factorial 並回答 6 4 接收訊息 factorial 並回答 24 6 接收訊息 具有 24 作為實際引數並回答 30 30 接收訊息 betweenand 具有 10 和 100 作為實際引數並回答 true 最後的訊息傳送的回答，是整個表示式的結果。 組合 在需要的時候使用圓括號可以改變求值的次序。例如： 3 factorial 4 factorial between 10 and 100 將改變表示式含義，首先計算 3 factorial 4 產生 10。接著 10 接收第二個 factorial 訊息，產生 3628800。3628800 接著接收 betweenand，回答 false。 注意由於二元訊息的含義，不是硬性規定入 Smalltalk80 語法的，它們全部都被認為有相等的優先順序，並簡單的從左至右來求值。因此，使用二元訊息的 Smalltalk 表示式的含義，可能不同於傳統釋義： 3 4 5 被求值為 3 4 5，產生 35。要得到預期回答 23，必須使用圓括號來顯式的定義運算次序： 3 4 5 複合 以點號分隔的表示式按順序執行。注意在變數定義和隨後的表示式之間沒有點號。一個表示式序列的值，是最後的表示式的值。除了最後的表示式之外，所有的表示式的值都被忽略。注意點號是分隔符而並非終結符，因此最終的點號是可選的。 下列（假想）例子中，書寫了一序列的表示式，每個都用點號分隔。這個例子首先建立類 Window 的一個新例項，儲存它在一個變數中，接著向它傳送兩個訊息： window window Window new window label Hello window open 級聯 如果像上述例子這樣，將一序列訊息都發送給相同的接收者，它們也可以寫為方法級聯呼叫，具有用分號分隔的單獨訊息： Window new label Hello open 這種將前面例子的重新為一個單一表達式，避免了對將新視窗儲存在臨時變數的需要。依據平常的優先順序規則，首先向 Window 類傳送一元訊息 new，接著向 new 回答的那個物件，傳送 label 和 open。 可以使用 yourself 訊息來返回一個級聯訊息的接收者。 程式碼塊 塊是頭等物件。程式碼塊即匿名函式，可以被表達一個文字值（它是一個物件，因為所有值都是物件）。這是透過方括號達成的： params 訊息表示式 這裡的params 是程式碼可以接受的形式引數的列表。結果的塊物件可以形成一個閉包：它可以在任何時間訪問它外圍的詞法作用域內的變數。這意味著下列 Smalltalk 程式碼： x x 1 可以理解為：f x x 1，或用 λ 演算表達為：lambda x x 1。 塊可以透過傳送給它們 value 訊息來執行。塊有一個引數用 value，有 2 個引數使用 valuevalue，以此類推直到 4 個引數，對多於 4 個引數使用 valueWithArguments 並將引數作為陣列傳遞。例如下面的表示式： x x 1 value 3 可以被求值為：f 3 3 1，或用 λ 演算表達為：lambda x x 13 underset betarightarrow 31。 塊返回（常稱為回答）其主體的最後一個表示式的值，除非有一個由顯式的 指示的返回，這時返回這個返回表示式的值。在塊內部的返回，充當了一種逃出（escape）機制。在一個巢狀的塊表達中的返回表示式，將終止在字面上包圍的方法。 塊的文字表示是一種創新，它一方面允許特定程式碼有更重大的可讀性；它允許涉及迭代的演算法一更清晰和簡潔的方式編碼。典型的在某些語言中使用迴圈寫成的程式碼，可以在 Smalltalk 中使用塊簡潔的書寫，有時在單一一行之內。更加重要的，塊允許使用訊息和多型來表達控制結構，因為塊推延了計算，而多型可以用來選擇交替者（alternative）。所以在 Smalltalk 80 中，ifthenelse 被書寫和實現為： expr ifTrue expr 為真時求值的語句 ifFalse expr 為假時求值的語句 再舉一例，向一個蒐集傳送訊息 select： positiveAmounts allAmounts select anAmount anAmount isPositive 注意這與函數語言程式設計有關，這裡的計算模式被抽象成了高階函式。select 等價於在一個適當的函子上的高階函式 filter。 控制結構 在 Smalltalk 中控制結構沒有特殊的語法。它們轉而實現為傳送到物件上的訊息。以條件執行為例，布林類 Boolean 定義了 ifTrue、ifFalse、ifTrueifFalse 和 ifFalseifTrue 方法。比如向一個布林物件，傳送 ifTrue 訊息，並傳遞一個程式碼塊作為實際引數，這個塊被執行當且僅當布林接收者為真。下面用一個例子來展示： result a b ifTrue greater ifFalse less or equal 塊也被用來實現，使用者定義控制結構、列舉器、訪問者、異常處理、可插拔的行為和很多其他模式。 迭代 下面例子，從一個字串中過濾出其中所含有的母音字元： aString vowels aString This is a string vowels aString select aCharacter aCharacter isVowel 在最後一行，向字串物件 aString 傳送一個 select 訊息，它具有一個程式碼塊 aCharacter aCharacter isVowel 作為實際引數。這個程式碼塊，表示一個測試，程式碼塊文字將被用作一個謂詞函式，它回答 true，當且僅當這個字串的一個元素 aCharacter，應當被包括在滿足這個測試的字元蒐集之中。 字串類 String 響應 select 訊息，要呼叫的 select 方法，定義並實現在蒐集類 Collection 中 Collection Method Definitions select aBlock Answer a new instance of a Collection containing all the elements in the receiver which when passed to aBlock answer true newCollection newCollection self copyEmpty self do element aBlock value element ifTrue newCollection add element newCollection ；它將給 select 的實際引數選擇塊，傳送給形式引數 aBlock；然後將綁定了選擇塊的 aBlock 嵌入到迭代塊的程式碼之中，再把這個迭代塊作為向字串自身傳送的 do 訊息的實際引數，從而將這個字串所包含的每個字元，都作為實際引數傳送給這個迭代塊，而各做一次求值。在求值迭代塊的時候，透過 value 訊息，將迭代元素傳送給 aBlock 所繫結的選擇塊，它回答一個布林值；接著向它傳送 ifTrue 訊息，如果這個布林值是物件 true，則將這個字元增加到要返回的字串中。 字串類 String 響應 do 訊息，要呼叫的 do 方法，定義在可迭代類 Iterable 中 Iterable Method Definitions do aBlock Enumerate each object of the receiver passing them to aBlock self subclassResponsibility ，而實現在可序列化蒐集類 SequenceableCollection 中 SequenceableCollection Method Definitions do aBlock Evaluate aBlock for all the elements in the sequenceable collection 1 to self size do i aBlock value self at i Interval Method Definitions do aBlock Evaluate the receiver for each element in aBlock i i start step 0 ifTrue i stop whileTrue aBlock value i i i step ifFalse i stop whileTrue aBlock value i i i step ，這個類是 Iterable 類的子類和 String 類的超類。 異常處理 Smalltalk 的異常處理機制，Exception 類及其子類比如 Error 類，類似於 CLOS 的異常處理樣式，使用塊作為處理器： 一些運算 Error signal an error occurred 另一些運算 on Error do ex 處理器程式碼 ex return 異常處理器的 ex 實際引數，提供對掛起運算的狀態的訪問，比如它的棧幀、行號、接收者和實際引數等，並且透過傳送 ex proceed、ex reject、ex restart 或 ex return 之一，還可用來控制計算怎樣繼續。 類 類透過例項變數定義它的例項的結構，透過方法定義它的例項的行為。每個方法都有叫做選擇子的一個名字，它在這個類之內是唯一性的。 定義 下面是個平凡的類定義： Object subclass MessagePublisher instanceVariableNames classVariableNames poolDictionaries category Smalltalk Examples 多數這種定義經常由程式設計環境來填充。這裡的類定義是給 Object 類的一個訊息，用來建立它叫做 MessagePublisher 的一個子類。 在 Smalltalk 中類是頭等物件，它可以就像任何其他物件一樣接收訊息，並可以在執行時間動態的建立。Object 類在收到這個 subclassinstanceVariableNamesclassVariableNamespoolDictionariescategory 訊息之時，原則上首先在其元類 Object class 中查詢對應方法，未果而上溯繼承鏈在其超類 Class 類中找到對應方法實現。 在 Smalltalk 中，是這個例項的私有變數，它可以在定義它們的類的任何例項方法中，還有在它的子類中定義的方法中，透過名字來訪問。在需要於一個類的所有例項、這個類本身和它的子類之間，共享某個資料的時候，要使用，它是由這個類和它的所有例項共享的私有變數。池變數是在可以沒有繼承關聯的多個類之間共享的變數。池變數最初儲存在池字典中，現在它們應當被定義為專門的類（SharedPool 的子類）的類變數。 category 指示有關的類的 群組，在現代 Smalltalk 版本如 Pharo 中被替代為 package，包系統是利用簡單的命名約定，組織 Squeak 和 Pharo 原始碼的簡單而輕量級的方式。 在一個類所對應的元類中定義的例項變數叫做類例項變數，每個類都有自己私有的類例項變數，子類將繼承這些類例項變數，但是子類會擁有這些變數的它們自己的私有複本，類和它們的子類不分享類例項變數。例如，可以定義一個類例項變數叫做 count 來跟蹤一個給定的類有多少例項。 類不能直接訪問它的例項的例項變數，而例項不能訪問它們的類的類例項變數。如果需要的話必須定義變異子與訪問子。 方法 當一個物件接收到一個訊息的時候，呼叫匹配這個訊息名字的一個方法。所有方法都是公開的和虛擬的（也就是動態查詢的）。方法被分組入指示它們意圖的協議（protocol）之中。 為一個類增加方法涉及到 Behavior 類，其中的 compile 方法，編譯一個方法原始碼並返回一個 CompiledMethod 類的例項；addSelectorwithMethod 方法，將給定的一個編譯過的方法增加到方法字典中。在 Behavior 類的子類 ClassDescription 類中，compileclassified 方法，編譯一個方法的原始碼，併為這個方法指派上給定的歸類（對於方法稱為協議）。 物件負責在執行時間動態的確定，執行哪個方法來響應一個訊息，儘管在很多語言中，這可能是（有時或總是）在編譯時間靜態確定的。下列程式碼定義一個方法 publish，並且這個定義將在這個物件收到 publish 訊息的時候發生。 publish Transcript show Hello World 下列名字為 quadMultiplyand 的方法，演示了接收多個實際引數並返回一個值： quadMultiply i1 and i2 這個方法將給定的兩個數相乘並對結果乘以 4 mul mul i1 i2 mul 4 執行任何前導了 （脫字元或）的表示式，都導致這個方法於這一點退出，並返回這個表示式的值。終止而沒有顯式返回某個表示式的一個方法，將隱含的返回自身。 例項化 為一個類新建一個例項，要用到 new 方法，它定義在 Behavior 類中。下列例子程式碼： MessagePublisher new 建立並返回 MessagePublisher 類的一個新例項。它典型的會被賦值到一個變數： publisher MessagePublisher new 但是也可以向一個臨時的匿名物件傳送一個訊息： MessagePublisher new publish 類方法 類方法就是在一個類的元類中定義的方法。 比如蒐集類 Collection 的類方法中，例項建立方法有 with、withwith Collection Method Definitions Collection class with firstObject with secondObject Answer a collection whose only elements are the parameters in the order they were passed self new add firstObject add secondObject yourself 、一直到 withwithwithwithwithwith 方法。在下面的例子中，將 withwith 用於有序蒐集類 OrderedCollection，它是 SequenceableCollection 類的子類，故而能最終上溯至超類蒐集類： rectangles aPoint collisions rectangles OrderedCollection with Rectangle left 0 right 10 top 100 bottom 200 with Rectangle left 10 right 10 top 110 bottom 210 aPoint Point x 20 y 20 collisions rectangles select aRect aRect containsPoint aPoint 反射 反射是一個計算機科學術語，適用於有能力檢查它們自己的結構的軟體程式，例如檢查它們的分析樹或輸入和輸出引數的資料型別。反射是動態、互動式語言比如 Smalltalk 和 Lisp 的一個特徵。具有反射的互動式程式（要麼解釋的要麼編譯的）維護所有記憶體內物件的狀態，包括程式碼物件自身，這是在解析 編譯期間生成的，並且是在程式設計上可訪問和修改的。 反射也是 Smalltalk 這種有元模型的語言的一個特徵。元模型是描述這個語言的模型，開發者可以使用元模型來做事，比如遊歷、檢查和修改一個物件的分析樹，或找到特定種類的結構的所有例項（例如在元模型中 Method 類的所有例項）。 Smalltalk80 是完全的反射式系統，用 Smalltalk80 語言實現。Smalltalk80 提供了結構性和計算性反射二者。Smalltalk 是結構性反射式系統，其結構是由 Smalltalk80 物件定義的。定義這個系統的類和方法也是物件，並且完全是它們所有助力定義的系統的一部份。Smalltalk 編譯器將文字原始碼編譯成方法物件，典型是的 CompiledMethod 的例項。透過把它們儲存入一個類的方法字典，而增加到這個類。類層級的定義類的那部份，可以向系統增加新類。這個系統是透過執行建立或定義類和方法的 Smalltalk80 程式碼來擴充套件的。Smalltalk80 系統是個現場（living）系統，承載著在執行時間擴充套件自身的能力。 因為類是物件，可以向它們提問比如：你實現了哪些方法？ 或 你定義了什麼欄位 槽 例項變數？。所以透過能應用於系統中的任何物件的普通的程式碼，物件可以輕易的檢查、複製、（去）序列化，諸如此類。 Smalltalk80 還提供計算性反射，有能力觀察系統的計算狀態。在派生自最初 Smalltalk80 的語言中，一個方法的當前活動（activation），可以作為透過偽變數命名的一個物件來訪問，這個偽變數是作為六個保留字之一的 thisContext。透過傳送訊息至 thisContext，一個方法活動可以提問比如：誰給你傳送了這個訊息？。這些設施使得有可能實現協程，或類似 Prolog 的回溯，而不需要修改虛擬機器。異常系統也是使用這個設施實現的。這個設施更有趣的用法之一，是在 web 框架之中，它透過為每個編輯的頁面儲存續體，並在它們之間切換來導航一個 web 站點，緩解了程式設計者處理 Web 瀏覽器的返回按鈕的複雜性。使用 Seaside 程式設計 web 伺服器，可以使用更常規的程式設計風格來完成。 Smalltalk 如何使用反射的一個例子，是處理錯誤的機制。當一個物件被髮送了一個它沒有實現的訊息的時候，虛擬機發送給這個物件 doesNotUnderstand 訊息，具有這個訊息的實化作為實際引數。這個訊息（它是另一個物件，是 Message 的例項），包含這個訊息的選擇子和它的實際引數的一個 Array。在互動式 Smalltalk 系統中，doesNotUnderstand 的預設實現，是開啟一個錯誤視窗（一個 Notifier）向用戶報告錯誤。透過它和反射設施，使用者可以檢查錯誤在其中發生的上下文，重新定義犯錯的程式碼，並繼續，這一切都在這個系統之中，使用 Smalltalk80 的反射設施。 透過建立只理解（實現）doesNotUnderstand 的一個類，可以建立一個例項，經由它的 doesNotUnderstand 方法能攔截髮送給它的任何訊息。這種例項可以叫做透明代理（proxy）。可以使用這種代理來實現很多設施，比如分散式 Smalltalk，這裡的訊息在多個 Smalltalk 系統之間交換，和資料庫介面，這裡的物件透明的從資料庫中排除錯誤，還有 promise 等。分散式 Smalltalk 的設計影響了如 CORBA 這樣的系統。 基於映像的持久儲存 多數流行的程式設計系統，將靜態的程式程式碼（以類定義、函式或過程的形式），分離於動態的或執行時間的程式狀態（比如物件或其他形式的程式資料）。它們在程式啟動的時候裝載程式程式碼，而任何先前的程式狀態必須從配置檔案或其他資料來源顯式的重新建立。程式（和程式設計者）未顯式儲存的設定，在每次重啟時都必須再次設立。傳統的程式在每次程式儲存一個檔案、退出和過載的時候，還失去很多有用的文件資訊。這會失去細節比如回退歷史或游標位置。基於映像的系統不會因為計算機關閉或 OS 更新，而強制失去所有這些東西。 但是很多 Smalltalk 系統，不區分程式資料（物件）和程式碼（類）。事實上，類也是物件。因此，多數 Smalltalk 系統，儲存整個程式狀態（包括類和非類物件二者）在一個檔案之中。這個映像可以接著由 Smalltalk 虛擬機器裝載，將類 Smalltalk 系統恢復成先前的狀態。這是受到了 FLEX 的啟發，它是 Alan Kay 建立的語言並描述於他的科學碩士畢業論文中。 Smalltalk 映像類似於（可重啟的）核心轉儲，並可以提供與核心轉儲相同的功能，比如延遲或遠端除錯，具有對出錯時刻的程式狀態的完全訪問。將應用程式碼建模為某種形式的資料的其他語言比如 Lisp，也經常使用基於映像的持久儲存。這種持久儲存的方法，對於快速開發是強力的，因為所有開發資訊（比如程式的解析樹），都儲存而利用於除錯。但是它作為一個真實的持久儲存機制，也有一個嚴重的缺點。首先，開發者可能經常想要隱藏實現細節，並使它們在執行時間不可獲得。出於法律和維護的原因，允許任何人在執行時間修改程式，對於在執行時間環境不暴露原始碼的編譯後的系統，不可避免的介入複雜性和潛在的錯誤。其次，儘管持久儲存機制易於使用，它缺乏多數多使用者系統需要的真正持久儲存能力。最明顯的是進行同多個使用者並行訪問相同的資料庫的事務。 實現列表 OpenSmaltalk OpenSmaltalk VM（OS VM）是 Smalltalk 執行時環境的著名實現，很多現代 Smalltalk VM 基於或派生自它。OS VM 自身是從一組 Smalltalk 原始碼檔案（它們叫做 VMMaker），轉譯成原生 C 語言原始碼（透過使用叫做 Slang 的轉譯器），它依次再針對特定平臺和硬體架構來編譯，實際上確使 Smalltalk 映像的跨平臺執行。原始碼可以在 GitHub 上獲得並在 MIT 許可證下發布。OS VM 的知名派生者有： Squeak，一個開源 Smalltalk。 Pharo Smalltalk，一個開源跨平臺語言。 Croquet VM，Croquet OS 的一個與 Squeak 有關的 Smalltalk VM。 CuisSmalltalkf，一個開源的小型、簡潔和適用的 Smalltalk。 HaverSmalltalk，Cuis 的具有完整模組系統的擴充套件。 JavaScript VM PharoJS，一個開源的從 Smalltalk 到 Javascript 的轉譯器，擴充套件了 Pharo 環境。 SqueakJS，用於 web 的一個 OpenSmalltalk 相容的 VM，還能執行老舊的 Squeak 應用如或 Scratch。 其他 ，透過轉譯執行在 JavaScript 上。 Smalltalk，包含下列產品：、ObjectStudio 和 WebVelocity。 ，一個家族，包括 SmalltalkV。 SmalltalkX，由 Claus Gittinger 開發。 ，在 2009 年寫的只用於 macOS 的實現。 ，GemTalk 系統出品。 GNU Smalltalk，Smalltalk 的無頭（缺少 GUI）實現。 ，GNUstep 指令碼框架，它在 ObjectiveC 執行時上使用 Smalltalk 語言。 Smalltalk。 VAST 平臺（VA Smalltalk），Instantiations 公司開發。 。 ，Object Arts 出品。 ，Object Connect 出品的 Windows 平臺 Smalltalk。 ，運行於 Palm Pilot。 SmallJ，一個開源的基於 Java 的 Smalltalk，派生自 SmallWorld。 ，用於學習的可視程式設計系統。 ，提供可選的強型別。 TruffleSqueak，用於 GraalVM 的一個 SqueakSmalltalk VM 和 Polyglot 程式設計環境（更多基於 GraalVM 的 Smalltalk 實現可見於官網 參見 GLASS 引用 延伸閱讀 外部連結 Free Online Smalltalk Books Smalltalk Zoo Smalltalk80 Bluebook implementations in C by dbanay and rochuskeller on github Category 面向物件的程式語言 Category 基於類的程式語言 CategorySmalltalk 程式語言家族 Category1972 年建立的程式語言