Simula67

**Simula**，一種編譯式的程式語言，由奧利 - 約翰・達爾與克利斯登・奈加特，在 1960 年代於奧斯陸的挪威計算中心，開發出來了 Simula I 與 Simula 67 兩代。它承繼了 ALGOL 60 作為基礎，被認為是第一個物件導向程式設計的程式語言。

Simula 67 介入了物件、類、子類（後來慣稱為子類繼承超類）、虛過程，還有協程、離散事件類比和特徵性的垃圾收集。Simula 的影響經常被低估，在 C++、Object Pascal、Modula-3、Java 和後來的很多程式語言中，都實現了受 Simula 啟發的物件。BETA 是 Simula 的現代後繼者。

## 歷史

克利斯登・奈加特在 1957 年開始在自己的電腦上寫模擬器。為了發展他的模擬器，他需要更強大的程式語言。1962 年 1 月，奧利 - 約翰・達爾開始跟他合作。他們受到 ALGOL 60 的啟發，在同年 5 月，發展出第一個模擬器程式語言，取名為 Simula I。此時，克利斯登・奈加特受到 Sperry Rand 公司邀請，去協助他們開發 UNIVAC 1107 電腦。UNIVAC 軟體部門的主管鮑伯・貝莫，力邀克利斯登・奈加特前往國際資訊處理協會（IFIP）舉行的第二次國際會議上，發表了論文「SIMULA－擴展 ALGOL 到離散事件網路的描述」。

1963 年 8 月，挪威計算中心（NCC）購買到 UNIVAC 1107，在 UNIVAC 的合約同意下，奧利 - 約翰・達爾在這台電腦上安裝以 ALGOL 60 的編譯器來實作的 Simula I。1965 年 1 月，Simula I 終於可以在 UNIVAC 1107 上完全的運作。接下來幾年，克利斯登・奈加特與奧利 - 約翰・達爾致力於教授 Simula I。Simula I 也被移植到 Burroughs B5500 電腦，以及蘇聯的 URAL-16 電腦上。

1965 年，東尼・霍爾首次提出「記錄類別」（record class）構造的概念，1966 年，克利斯登・奈加特與奧利 - 約翰・達爾通過將 Simula I 的進程當作由前綴層和主要層二者構成，把它擴展成了具有了記錄類別屬性的通用進程，他們當時所稱「進程」隨即被稱為「物件」。1967 年 5 月，奈加特和達爾在奧斯陸舉辦的 IFIP 工作小組論壇中，發表了關於類別與子類別聲明的論文，形成 Simula 67 的第一份定義檔案。

1968 年召開的會議，組成了 SIMULA 標準小組，並發表了第一份官方 Simula 標準檔案「SIMULA 67 通用基礎語言」。在 1960 年代後期和 1970 年代早期，Simula 67 主要實現於四個系統之上：挪威計算中心的 UNIVAC 1100 系列，挪威計算中心的 IBM System/360 和 System/370，奧斯陸大學在 Kjeller 聯合安裝的 CDC 3000 系列，和瑞典國防研究所（FOA）的 DEC TOPS-10。

當前的 Simula 67 業界標準，是在 1986 年修訂的「標準 SIMULA」，它在 1987 年被接受為瑞典國家標準。它有四個主要實現：Simula AS、Lund Simula、GNU Cim 和 Portable Simula Revisited。

Simula 影響了 Smalltalk，和後來的物件導向程式設計語言。Simula 經由 Smalltalk 啟發了並行計算的演員模型。C++ 語言和 Java 語言的創始人，都認可自己受到了 Simula 的重要影響。

## 特徵概念

Simula 67 包含通用演算法語言 ALGOL 60 的多數特徵作為自己的子集。它是大小寫不敏感的。

### 塊與過程

ALGOL 60 中最強力的編程構造機制之一，就是塊和過程的概念。

#### 語法

塊是一種語句，在 Simula 67 中，它包括子塊和有字首（prefixed）塊。子塊就是未加字首的常規意義上的塊，下面分別用字母 `D` 表示任意聲明，`S` 表示任意語句，`L` 表示可選的任意標籤，子塊的語法單元採用的形式為：

聲明擔當定義在程式中用到的量的特定屬性，並給它們關聯上識別碼，這裡的量（quantity）包括：簡單變數、陣列、`switch`、過程、類和外來聲明。塊中的每個語句，都可以是完全的複合語句或塊。複合語句與塊相比沒有聲明。所有的塊，自動地介入一層新的命名法（nomenclature）：

* 在這個塊內出現的識別碼，可以通過合適的聲明，而被指定為局部於所論及的這個塊。在這個塊內側的這個識別碼所表示的實體，不存在於它的外側。在這個塊外側的這個識別碼所表示的任何實體，在這個塊內側是不可見的；在 Simula 67 中，可通過連接或遠端存取使它成為可見的。
* 除了表示標籤的識別碼之外，一個識別碼，如果出現在一個塊中，而且並非聲明於這個塊中，則它非局部於這個塊，就是說它所表示的這個塊內側實體，與在緊接它外側的層級中出現的同名實體是同一個實體。因為塊中的語句自身可以是一個塊，局部和非局部於一個塊的概念，必須遞迴地去理解，就是說非局部於一個塊 `A` 的一個識別碼，可是亦可否地，非局部於 `A` 是其中語句的塊 `B`。

#### 語意

塊是一種形式描述或模式，關乎聚集的資料結構和關聯的演算法以及行動。一個塊實例，可以被認為是它的形式描述的文字複本。一個塊的任何內部塊，仍然是一個模式，但是在其中出現的非局部識別碼，確認了局部於字面上包圍的塊實例的專案。

* 當一個塊執行的時候，生成這個塊的一個動態實例。在電腦中，一個塊實例可以採用一種形式的記憶體區域，它包含需要的動態塊資訊，並包括空間來持有局部於這個塊的變數的內容。
* 塊實例中的局部變數，標識了分配給塊實例的記憶體片段。非局部於內部塊的識別碼繫結，對這個內部塊的任何隨後的動態實例，保持有效。

任何聲明的變數，在進入這個變數所局部於的那個塊之中的時候，都會被初始化。局部於一個塊的一個變數，是一個記憶體裝置，其內容依據這個變數的類型，要麼是一個值，要麼是一個參照。值類型可特徵化為直接關聯著一個可能值的集合（這個類型的「值範圍」）。參照概念，對應於一個名字或一個「指標」的直觀想法。它提供了參照值的機制，還反映了機器的定址可能性。在特定簡單情況下，一個參照可以被實現為一個儲存的值的記憶體位址。對於值類型不關聯著參照概念。

過程與塊相比，它有一個名字，可以在程式的多個不同地方提及，並且在呼叫時可以給出參數；過程的參數傳送模態，除了有傳值呼叫和傳名呼叫，在 Simula 67 中，又增加了傳參照呼叫。過程和塊都不可能建立到它或它內部的參照；對於一個給定塊，有可能生成它的一些可以共存和互動的實例，例如遞迴過程的實例。

* 定義函式指示符的值的過程，以類型聲明符作為其過程聲明的最先符號。此外的真正（proper）過程，在 Simula 67 中，被稱為具有普遍（universal）類型，任何類型都從屬（subordinate）於普遍類型。在 Simula 67 中，過程的參數列 `( … <参数分界符> … )`，捨棄了其中對 ALGOL 60 是可選的「`) <字母串>: (`」樣式的參數分界符。
* 過程的預設的傳送模態，在 Simula 67 中，對於值類型的參數是傳值呼叫，對於所有其他類型的參數是傳參照呼叫；故而在過程聲明的參數規定中，增加了以 `name` 為前導的名字部份，用來指定所述及的參數採用傳名呼叫。在過程主體內傳名呼叫的形式參數的每次出現，都引起對實際參數的一次求值。在 Simula 67 中，這個求值發生在過程語句的上下文中，就是說不會出現識別碼衝突，因為過程主體和它的變數此時是不可見的。
* 過程呼叫的執行，在有參數的情況下要經歷如下步驟：建立形式參數塊實例；求值對應於傳值呼叫或傳參照呼叫的實際參數，並將其結果賦值給形式參數塊實例的對應變數；過程主體被初始化並開始執行。

塊實例的想法，在 Simula 67 中還進一步產生出，一個塊作為「物件」的「類」的概念，這些物件每個都是這個塊的動態實例，因此符合相同的模式。介入擴充的塊概念，要通過類別宣告和關聯的互動機制，比物件參照、遠端存取、准並列運算和塊串接。

### 物件與類

Simula 67 的中心概念是物件，一個物件是一段自備式（self-contained）程式（塊實例），它擁有由一個類聲明定義的自己的局部資料和行動（action）。操縱物件和相互關聯物件的需要，致使語言必須介入列表處理設施。

類是一種過程，它有能力引起在它被呼叫後仍存活的一個塊實例，而這些實例就叫做這個類的物件。類別宣告定義一個程式（資料和行動）模式，而符合（conforming）這個模式的物件被稱為「屬於相同的類」。

* 對於一個給定物件，形式參數，在由 `virtual:` 前導的虛擬部份中規定的量，和聲明為局部於類主體（body）的量，叫做這個物件的特性（attribute）。一個特性的聲明或規定叫做特性定義。在 1986 年修訂的語言標準中，通過由 `hidden` 亦或 `protected` 前導的保護規定，可以限制類特性識別碼的可見性。
* 類別宣告的形式參數，不適用傳名呼叫。在規定部份中需要對每個形式參數進行規定，這些參數被當作局部於類主體的變數，可以接受如下規定符（specifier）：`<类型>`、`array` 和 `<类型> array`。
* 類主體通常是一個塊，即使它如語法形式所允許的那樣是塊以外的一個語句，也表現得如同一個塊。一個分裂（split）主體，擔當其中符號 `inner` 表示一個虛設（dummy）語句的塊。

不同於後來的將物件作為記錄或結構的擴充的物件導向程式設計語言，Simula 67 的類主體中除了有定義特性的聲明，還可以有定義行動的語句。如果有行動定義在一個類別宣告中，則符合這個模式的行動，可以由屬於這個類的所有物件執行。如果在類別宣告中沒有指定行動，則定義了一類純資料結構。例如：

屬於特定類的物件，通過物件表達式，用物件生成語句 `new` 來生成。例如，想要多少就能生成多少屬於這個 `Order` 類的一個新物件：

屬於一個物件的行動，可以都在就一個過程而言的一個序列中執行。這些行動，還可以作為一系列的獨立子序列或「活動階段」（active phase）來執行。在一個給定物件的兩個活動階段之間，可以出現任何數目的其他物件的活動階段。

Simula 67 為了將整個程式執行組織為屬於物件的活動階段的一個序列，而包含了其所必需的基本特徵。在模擬器類 `Simulation` 的聲明中，定義了叫做「定序集合」（sequencing set）的一個「時間軸」，它也是充當佇列的一個雙向列表，還有行程類 `Process`，它給與物件將其活動階段通過時間軸來組織的一種屬性。

### 子類

一個類可以被用作到另一個類別宣告的「字首」，從而將字首所定義的屬性，建造入這個新的類別宣告定義的物件之中。具有字首 `C` 和類識別碼 `D` 的一個類別宣告，定義了類 `C` 的一個子類 `D`。不同於後來的物件導向程式設計語言所稱謂的衍生類別擴充基礎類，或子類繼承超類（父類別），在 Simula 67 中，類 `D` 被稱為內部（inner）於類 `C`，而類 `C` 被稱為外部（outer）於類 `D`。

設 `Cn` 是具有字首序列 `C1, C2, ...... Cn-1` 的一個類，這裡 `Ck`（`k = 1,2,...,n`）的下標 `k` 叫做字首層級，則屬於 `Cn` 的物件是一個複合物件，它可以用串接的類別宣告來正式的描述，串接的過程被認為先於程式執行而發生。
設 `X` 是屬於 `Cn` 的的一個物件。非正式的說，串接機制有如下結果：

* `X` 擁有的特性集合，是在 `C1, C2, ... , Cn` 中所定義集合的併集。在 `Ck`（`1 <= k <= n`）中定義的特性，被稱為定義在字首層級 `k`。
* `X` 擁有的「運算規則」，構成自來自在這些類的主體的語句，並且它們依據了預先規定的次序。來自 `Ck` 的語句，被稱為屬於 `X` 的字首層級 `k`。
* 在 `X` 的字首層級 `k` 的語句，能存取在 `X` 的等於或外部於 `k` 的字首層級上定義的它的所有特性，但是不能直接存取由於在外部於 `k` 層級的衝突定義而導致不可見的特性。這些不可見特性仍然可以存取，例如通過使用過程或 `this`。
* 在 `X` 的字首層級 `k` 的語句，不能立即存取在 `X` 的內部於 `k` 的字首層級上定義的它的那些特性，除非通過虛擬量。
* 在字首層級 `k` 的分裂主體中，符號 `inner`，表示 `X` 的屬於內部於 `k` 的字首層級的運算規則的那些語句，或者在 `k = n` 時表示虛設語句。如果 `C1, ... , Cn-1` 都沒有分裂主體，則在 `X` 的運算規則中的那些語句，依據升序字首層級來排序。

下面是一個簡單例子：

屬於這些子類如 `BatchOrder`、`SingleOrder` 和 `Plate` 的新物件，都有為 `Order` 定義的資料，再加上在各種類別宣告中定義的補充資料。例如，屬於類 `Plate` 的物件，構成自如下資訊片段：`Order` 定義的 `number`、`numberOfUnits`、`arrivalDate` 和 `processingTime`，`SingleOrder` 定義的 `setupTime` 和 `finishingTime`，`Plate` 定義的 `weight`、`length` 和 `width`。

有字首（prefixed）塊的一個實例，是由塊字首生成的物件，與這個主體塊的實例，串接而成一個複合物件，其串接定義類似於類的串接規則。塊字首的類的形式參數，按塊字首的實際參數所示初始化。對有字首塊有兩個限制：在其中通過使用 `this` 來參照到類自身的類，是非法的塊字首。一個塊字首的類識別碼所提及的類，必須局部於最小的包圍這個有字首塊的塊。

### 參照

當屬於各種類的很多物件，作為同一個程式的各部份而共存的時候，需要能夠對個體物件指定名字，為此介入了叫做「參照」的新的基本類型；還要能相互關聯物件，比如通過二元樹和各種其他類型的列表結構，為此將叫做「集合」的迴圈雙向連結串列，作為一個系統類 `Simset` 介入為語言的一部份。

在 Simula 67 中有兩種參照類型，物件參照類型和文字參照。對於一個類物件（類別實例），有一個關聯的唯一的「物件參照」確認這個物件，並且對於任何類 `C`，都有一個關聯的物件參照類型 `ref (C)`。這種類型的量，被稱為由類 `C` 限定；它的值，要麼是一個物件，要麼是表示「沒有物件」特殊值 `none`。

限定（qualification）將值的範圍，限制至包括在限定類中的這些類的物件。不管何種限定，值的範圍都包括值 `none`。一個物件參照的限定，是一個類識別碼，它因此服從聲明的作用域和可見性規則。限定關聯於所提及的類別宣告局部於的那個塊的一個實例。這蘊涵著特定的關於限定有效性的檢查，不能單獨在程式正文的基礎上進行，因此這種測試必須在程式執行期間完成。

參照是有限定的，蘊涵著一個給定參照所提及的物件，只能屬於這個限定中提到的類，或屬於這個限定類的子類。如果一個物件參照類型的限定，是另一個物件參照類型的限定類的子類，則前者被稱為從屬於後者。例如：

物件表達式是獲得對一個物件的參照的一種規則。物件表達式的值，是被參照的物件或 `none`。製作一個參照來提及一個特定物件的運算子，寫為 `:-` 並讀作「指稱」（denote），它指示將一個參照，賦值給在參照賦值左側的、參照類型變數或參照類型過程識別碼。例如：

而運算子 `:=` 讀作「成為」（become），指示將一個值，賦值給在值賦值左側的、值類型變數或值類型過程識別碼，或者將一個文字值，賦值給在左側者所參照的文字影格（frame）。

### 物件表達式

物件表達式，具有類型 `ref(限定)`。物件表達式的限定規則包括：物件生成式、局部物件或限定物件，分別由跟隨符號 `new`、`this` 或 `qua` 的識別碼的類來限定。

物件生成式（generator），涉及到屬於所確認的類的物件的生成和執行。這個物件是相應的（串接成的）類的一個新實例。物件生成式的求值構成自如下行動：

1. 生成這個物件，並且這個物件生成式如果有實際參數，則求值它們，將得到的這些值及或參照傳送給形式參數。
2. 控制經過這個物件最初的 `begin` 進入其中，藉此它變成在「系附」狀態下執行。在生成的物件執行了 `detach` 基本過程，或者經過這個物件最終的 `end` 登出的兩種情況之一時，物件生成式的求值完成。

求值之後的物件的狀態，要麼是「脫離」要麼是「終止」，詳見後面的塊實例章節。

局部物件 `this C`，如果用在類 `C` 或 `C` 的任何子類的類主體中，或用在其塊限定為類 `C` 或 `C` 的一個子類的連接塊中，則這個物件表達式是有效的。在一個給定的上下文中，一個局部物件的值，是一個物件或連接到一個物件，它是這個物件表達式在其中有效的、最小的字面上包圍的塊實例；如果沒有這樣的塊，則這個物件表達式在這個上下文中是非法的。對於一個過程或類主體的實例（上下文），「字面上包圍」意為包含它的聲明。如此定義的內涵參見範例章節中的二元樹實例。

設 `X` 表示一個簡單的參照表達式，而 `C` 和 `D` 是類識別碼，使得類 `D` 是物件 `X` 的限定。對於限定物件 `X qua C`，如果類 `C` 外部於或等於類 `D`，或者是 `D` 的一個子類，則這個物件表達式是合法的，否則是為非法。如果 `X` 的值是 `none`，或者是屬於外部於 `C` 的類的一個物件，則這個物件表達式求值形成一個執行時間錯誤；在其他情況下，`X qua C` 的值，就是 `X` 的值。這種對一個串接的類物件的即時限定，約束或擴充它的特性通過檢視或遠端存取的可見性。

物件關係表達式，使用運算子 `is` 和 `in`，來測試一個物件的類成員關係。關係 `X is C`，在 `X` 參照屬於類 `C` 的物件之時，值為 `true`，否則值為 `false`。關係 `X in C`，在 `X` 是參照屬於 `C` 的物件，或者 `X` 是內部於 `C` 的類之時，值為 `true`，否則值為 `false`。

不同於算術關係表達式使用比較運算子 `=` 和 `<>`，物件參照關係表達式，使用比較運算子 `==` 和 `=/=`，來比較參照，從而區別於對應的被參照的值。兩個物件參照 `X` 和 `Y`，在它們都參照相同的物件，或者它們都是 `none` 之時，被稱為是「同一」的。關係 `X==Y`，在這種情況下擁有的值為 `true`，否則值為 `false`。關係 `X=/=Y` 的值，是 `X==Y` 的值的否定。

### 遠端存取

一個物件的一個特定特性，由下列三項資訊來完全確認（identify）：

1. 這個物件。
2. 外部於或等於這個物件的類的一個類。
3. 在這個類中或在屬於它的字首序列的任何類中定義的一個特性識別碼。

對於任何特性確認，第 2 項類資訊都是在字面上定義的，從而形成靜態繫結。屬於其他物件的特性，可以要麼通過「遠端識別碼」（「點表示法」），要麼通過「連接」（connection）機制，從其外側「遠端存取」來參照和使用。遠端識別碼的形式為：`简单对象表示式.特性标识符`，它可用作簡單變數、陣列變數、函式指示符（designator）和過程語句中的識別碼，這種點表示法給出對資訊的單獨片段的存取，例如：

它將名為 `next` 的類 `Order` 的物件的特性 `number`，比較於名為 `previous` 的類 `Order` 的物件的特性 `number`。

「組存取」可通過「連接語句」來完成，連接機制的用途，是為在連接塊中的特定辨識，提供上述第 1 項物件資訊和第 2 項類資訊的隱式定義。例如：

在檢視（inspection）塊的 `begin` 和 `end` 之間的語句中，可以直接提及 `next` 所參照的在 `Plate` 中包含的所有資訊片段。`do` 後面的語句，如果是塊以外的一個語句，它表現得也如同一個塊。連接語句進而表現得如同被叫做「連接塊」的第二個虛構（fictitious）的塊所包圍。

設物件表達式求值為 `X`，在連接塊執行期間，稱物件 `X` 為「被連接上」了。連接塊有一個關聯的「塊限定」，它是連接塊的前導類識別碼，而對於沒有 `when` 子句的情況，它是連接塊的前導物件表達式的限定。

### 虛過程

虛擬（virtual）量，有雙重用途：

* 允許在一個物件的一個字首層級上，存取在內部字首層級上聲明的特性。
* 允許在一個字首層級上的特性重新定義，在外部字首層級上有效。

在類別宣告的虛擬部份中，可以接受如下規定符：`label`、`switch`、`procedure` 和 `<类型> procedure`。不同於一般的特性確認，虛過程形成半動態繫結，在某種意義上類似於 ALGOL 60 的傳名呼叫機制。

一個物件的一個虛擬量，要麼是「無匹配的」的，要麼被確認為具有一個「匹配」特性，它是在這個虛擬量的字首層級上或在內部字首層級上聲明的，其識別碼重合（coincide）於虛擬量的識別碼的一個特性。匹配特性必須與虛擬特性有相同的種類。在一個給定字首層級上的匹配量的類型，必須重合或從屬於這個虛擬規定的類型，和在任何外部字首層級上聲明的任何匹配量的類型。

在 1986 年修訂的語言標準中，虛過程量可選的可使用 `procedure <过程标识符> <过程规定>` 方式來指定，即憑藉它的類型，並且如果它有形式參數，則還憑藉它們的類型、種類和傳送模態。含有過程規定 `is <过程声明>` 的虛過程量，只能由有相同類型的過程來匹配，並它與這個過程規定具有相同的過程頭部。

例如，下面實現雜湊表的 `Hashing` 類，聲明了虛過程 `hash` 並隨即實現了它，又定義了要用到雜湊過程 `hash` 的尋找過程 `lookup`:

子類 `ALGOL_hash` 和有字首塊，用自己的 `hash` 過程實現替代了其字首中的實現。在子類的類主體和有字首塊的主要塊中，能獲得到過程 `lookup`，而它用到的過程 `hash` 是這裡提供的替代實現。

### 作用域和可見性

一個識別碼定義及其關聯的識別碼，在其作用域與可見性之間需要做出區別。

* 一個識別碼定義的作用域，是它在其中可能有作用的那一部份程式正文。相同的識別碼，可以定義在程式的很多地方，因此可以關聯於不同的量。這種相同的識別碼的作用域，因而可能重疊，例如當一個識別碼在內部塊中被重新聲明的情況下。
* 一個識別碼定義，這個識別碼在程式的一個給定點上，如果能夠涉及到所論及聲明的量，則這個定義被稱為在這個點上是可見的。在給定識別碼於此可見的程式正文的一個特定點上，最多只能有一個定義關聯於這個識別碼，例如在上述重新聲明的情況下，在它們作用域的併集內任何給定點上，只有一個定義是可見的。

一個識別碼定義的局部塊，是在字面上最近的包圍塊，即子塊、字首塊、過程主體或類主體，還包括圍繞 `for` 語句的受控語句、過程聲明或類別宣告的虛構的塊、連接塊等等。這個識別碼和它的定義，被稱為局部於這個塊。
識別碼定義，只在它們的作用域內是可見的。一個特定定義的可見性，在它的作用域內可以受到下列限制：

* 具有相同識別碼的一個識別碼定義，即這個識別碼的重新定義，出現在以前的定義的局部塊所包圍的某個構造內。在它們共同的作用域內，只有最內部的重新定義是可見的。
* 一個重新定義，出現在類的某個內部字首層級。
* 遠端存取，可以導致某些識別碼定義在檢視塊或點表示法內變成不可見的。
* 使用 `this` 或 `qua`，可以導致一個或多個重新定義被臨時停止。
* 這個定義所局部於的類別宣告的保護部份。

一個識別碼的重新定義，不允許出現在它的局部塊的頭部，這禁止了在同一個塊中出現相同識別碼的兩個定義。

具有形式參數的過程，在特定意義上表現得如同有一個虛構的塊包圍著過程主體。形式參數因而對應於聲明為局部於這個虛構的塊的變數。因此，一個過程的形式參數，可以在屬於這個過程聲明的過程主體的頭部內被重新定義。這種重新定義，將這個形式參數的可見性，有效的限制至與它有關的 `value` 部份、`name` 部份和規定部份。因此這種參數的唯一作用，是來自其求值可能有的副作用。

除非在它的定義之內，一個識別碼的所有出現，都具有動態方面。這樣的一個識別碼，不僅涉及它的靜態定義，還涉及到從這個定義所局域於的那個聲明生成的某個物件。例如，在一個過程或類別宣告之內出現的一個形式參數識別碼，參照這個過程或類的某個實例化的物件。

### 塊實例

一個程式執行的組成部份，都是塊即子塊、有字首塊、連接塊和類主體的動態實例。一個塊實例，被稱為「局部於」直接包含它的描述文字的那個塊實例。例如一個給定類別的實例，局部於包含這個類別宣告的塊實例。最外層塊的實例不局部於塊實例。

在任何時間，「程式順序控制」（Program Sequence Control），首字母簡寫為 PSC，參照在一個塊實例中當前被執行的程式點；PSC 被「定位」於這個程式點並被這個塊實例所「包含」。進入任何塊，都涉及到生成這個塊的一個實例，於是 PSC 進入這個塊實例，到達它的第一個可執行語句上。

一個塊實例在任何時間，都是處在四種執行狀態之一：系附（attached）、脫離（detached）、恢復（resumed）或終止（terminated）。沒有在字面上給出字首的任何類，都被定義為字首了一個虛構（fictitious）的類，它只有一個特性即 `detach` 過程，因此所有類物件或有字首塊的實例，都擁有 `detach` 過程。在環境類 `ENVIRONMENT` 中，還定義了用於排程的 `call` 過程和 `resume` 過程。

* 一個非類塊實例，也就是有字首塊、子塊、過程主體或連接塊的實例，總是在系附狀態下，這個實例被稱為系附到了導致它生成的那個塊上。因此一個過程體的實例，系附到包含對應函式指示符或過程語句的塊實例上。非類、非過程塊實例，系附到它所局部的塊實例。在 PSC 到達非類塊實例的最終的 `end` 的時候，PSC 返回到緊隨導致這個塊實例生成的語句或表達式的程式點。
* 一個物件，最初是在系附狀態下，並被稱為系附到包含對應物件生成語句的那個塊實例上。一個物件，可以通過執行 `detach` 語句，進入脫離狀態。通過執行 `call` 語句，可以使一個脫離狀態的物件重新進入系附狀態，它藉此變為系附到包含這個呼叫語句的那個塊實例上。通過執行 `resume` 語句，可以使一個脫離狀態的物件進入恢復狀態。不使用 `detach`、`call` 或 `resume` 語句的一個程式執行，是一個簡單的系附狀態的塊的巢狀結構。
* 當 PSC 通過一個物件的最終 `end`，或通過 `goto` 語句離開它的時候，這個物件進入終止狀態。沒有塊實例系附到一個終止狀態的類物件上。終止狀態的物件，仍作為一個資料項而存在，它可以通過針對這個物件的包括過程和函式特性的這些特性的遠端標識來參照。

每當一個塊實例不復存在，局部於或系附於它的所有塊實例也不復存在。一個物件的動態作用域，因而受限於它的類別宣告的作用域。在 Simula 67 最初標準中曾提到過，語言實現可以使用垃圾回收技術，來進一步縮減一個物件的有效壽命的跨度。一個陣列聲明的動態作用域，可以擴充超出包含這個聲明的塊實例的作用域，因為傳參照呼叫參數傳送模態適用於陣列。

### 准並列系統

一個準並列系統，由一個子塊或有字首塊的任何實例所標識，它包含局部的類別宣告。這個標識一個系統的塊實例，叫做「系統頭領」。最外層的標識一個系統的塊實例，被稱為「最外層系統」。一個準並列系統，由「組件」（component）構成。組件是塊實例組成的巢狀結構，其中標識這個組件的一個塊實例，叫做「組件頭領」。

在每個系統中，組件中有一個被稱為「主幹組件」，在 Simula 67 最初標準中叫做「主程式」，其他組件叫做「物件組件」。一個系統的主幹組件的頭領（head），重合（coincide）於系統頭領，它總是處在系附狀態。一個系統的物件組件的頭領，確切的就是局部於系統頭領的那些脫離狀態的或恢復狀態的物件。

* 在任何時間，在一個系統的組件之中，有確切的一個組件被稱為「生效」（operative）的。不生效的組件，有關聯的「重新啟用點」，它標識在這個組件被啟用（activate）時，要在它那裡繼續執行的程式點。一個物件組件是生效的，若且唯若這個組件的頭領處在恢復狀態。
* 除了系統組件，程式執行還可以包含不屬於特定系統的「獨立物件組件」。任何這種組件的頭領，都是一個脫離狀態的物件，它局部於一個類物件或過程主體的一個實例，也就是說不局部於系統頭領（子塊或有字首塊的實例）。根據定義，獨立組件總是不生效的。

稱謂一個塊實例 `X` 被一個塊實例 `Y`「動態包圍」，若且唯若存在一個塊實例序列：`(X = Z0) → Z1 → .... → Zn-1 → (Zn = Y)` `(n>=0)`，使得對於 `i= 1,2,...,n` 有著：`Zi-1` 系附到 `Zi`；或者 `Zi-1` 是一個恢復狀態的物件，它關聯的系統頭領系附到 `Zi`（而這個系統頭領自身不在這個序列中）。終止狀態和脫離狀態的物件，不被除了自身之外的塊實例動態包圍。

* 將當前包含 PSC 的塊實例動態包圍起來的塊實例鏈，叫做「執行鏈」。在執行鏈上的塊實例，被稱為「執行」（operating）的，最外層的塊實例總是執行的。一個系統如果有一個組件是執行的，它就是執行的；在任何時間，一個系統最多有一個組件是執行的；執行的系統的頭領，可以是不執行的（不在執行鏈上）。一個執行的組件 ，總是生效的；如果一個系統的生效組件是不執行的，則這個系統也是不執行的。在不執行的系統中的生效的組件，是當這個系統成為不執行的時候在執行的組件，當這個系統再次成為執行的時候它將仍是執行的。
* 對於一個不生效的組件 `C`，如果一個塊實例 `P` 包含了它的重新啟用點（而 `C` 的重新啟用點關聯於 `C` 的頭領），則 `P` 被 `C` 的頭領動態包圍，並且 `P` 除了自身之外不動態包圍塊實例。由 `P` 與 `C` 的頭領 `X`「動態合圍」的塊實例序列 `(P = Z0) → Z1 → .... → Zn-1 → (Zn = X)` `(n>=0)`，被稱謂為 `C` 的「重新啟用鏈」。除了 `C` 的頭領 `X`（脫離狀態的物件）之外，這個鏈上的所有組件頭領（恢復狀態的物件），標識了生效而不執行的組件。在 `C` 成為執行的時候，在它的重新啟用鏈上所有塊也成為執行的。

組件的定序（sequencing），由 `detach`、`call` 和 `resume` 支配。`detach` 針對隱式指定的一個物件進行操作，而 `call` 和 `resume` 顯式指定所操作的物件。

### 定序

准並列系統的 `detach`/`resume` 機制，是一種協程。在 Simula 67 最初標準中，沒有恢復狀態，並且沒有規定 `call`，但 `call` 通常會出現在當時的語言實現中。`detach`/`call` 機制，相當於現在稱為生成器的「半協程」，而最初標準中的 `resume` 可理解為 `detach` 與 `call` 的組合。1986 年修訂的語言標準，增補定義了 `call`，新增了恢復狀態，並且重新定義了 `resume`，它不可再理解為 `detach` 與 `call` 的組合。

准並列系統，被建立於進入包含局部的類別宣告的一個子塊或有字首塊的時候，藉此生成的實例成為這個新系統的頭領。初始時，這個主幹組件是生效的，並且是這個系統唯一的組件。

建立一個物件組件，要通過針對一個系附狀態的物件，執行 `detach`，藉此 PSC 返回到這個物件系附到的那個塊實例。這個物件進入脫離狀態，並成為一個新的不生效的組件的頭領，這個組件的重新啟用點被定位到緊後於這個 `detach`。如果這個物件局部於一個系統頭領，則這個新的組件成為這個關聯的系統的成員。

通過 `detach` 和 `call`，可以形成「半對稱定序」，這隻涉及到物件組件，而不區分它們是屬於系統的組件還是獨立組件。

* 對於一個不生效的物件組件，通過針對它的脫離狀態的頭領，執行一個 `call`，可以重新啟用這個組件，藉此 PSC 移動到它的重新啟用點上。這個頭領重新進入系附狀態，並變成系附到包含這個 `call` 的塊實例上。這個組件正式的失去了本身（作為組件）的狀態。

通過 `detach` 和 `resume`，可以形成「對稱組件定序」，這隻涉及到屬於一個準並列系統的那些組件。對立於半對稱定序中的「呼叫者」與它的「被呼叫者」，在對稱組件定序中的「恢復者」與它的「被恢復者」，具有完全的對稱聯絡。

* 對於這個系統的一個不生效的物件組件，通過針對它的脫離狀態的頭領，執行一個 `resume`，可以重新啟用這個組件，藉此 PSC 移動到它的重新啟用點上；這個組件的頭領進入恢復狀態，而這個組件變成生效的。這個系統以前生效的組件變成不生效的，並且它重新啟用點被定位到緊後於這個 `resume`；如果這個組件是一個物件組件，則它的頭領進入脫離狀態。
* 對於當前生效的物件組件，通過針它的恢復狀態的頭領，執行一個 `detach`，這個系統的主幹組件重獲生效的狀態，藉此 PSC 移動回到主幹組件的重新啟用點上。以前生效的組件變成不生效的，並且它重新啟用點被定位到緊後於這個 `detach`。這個組件的頭領進入脫離狀態。

PSC 經過一個類物件的最終 `end` 的效果，除了使這個物件成為終止狀態，而非脫離狀態之外，相同於針對這個物件執行 `detach` 的效果。其結果是它不會得到重新啟用點，並且在它已經擁有作為組件頭領的狀態時，失去這種狀態。

## 程式範例

### 最小程式

按原始碼大小來衡量的話，空電腦檔案是 Simula 67 中最小的程式，它只包含一個東西，就是虛設語句。但是，最小的程式更經常表示為空塊：

它開始執行並立即終止。語言缺乏來自程式的任何返回值。

### Hello, World!

Simula 67 的經典 Hello, World! 範例：

`OutText` 過程將字串輸出到緩衝區，而 `OutImage` 過程將緩衝區內容輸出到標準檔案，二者都定義在輸出檔案類 `OutFile` 中，而它是檔案類 `File` 的子類。

### 傳名呼叫

使用傳名呼叫可以輕易實現 Jensen 裝置，一個簡單的例子是合計函式 $\sum _{k=m}^{n}{u}$ ，它可以實現如下：

這個例子對受控變數 `k` 和表達式 `u` 使用了傳名呼叫。這允許將受控變數 `k` 用於表達式 `u` 之中。由於 Simula 67 的 `for` 迴圈中受控變數，不能是傳名呼叫的形式參數或過程識別碼，故而上述代碼使用了 `while` 迴圈。

公式 $Z=\sum _{i=1}^{100}{1 \over (i+a)^{2}}$ 可以實現為如下：

### 協程

Simula 67 標準通過如下實例來詮釋叫做「准並列系統」的協程機制：

這個例子程式中，有兩個准並列系統 `S1` 和 `S2`。`S1` 是最外層系統，它包含了兩個類別宣告 `C1` 和 `C2`。`S2` 巢狀入了類 `C2` 的類主體之中，它包含了一個類別宣告 `C3`。

在 PSC 進入最外層子塊後產生系統 `S1` 的系統頭領，到達第 23 行的系統 `S1` 主幹組件的第一個可執行語句，開始生成物件 `X1`，進入類 `C1`，PSC 到達第 5 行的類主體的第一個可執行語句，呼叫了類 `C1` 的特性過程 `P1`，進入第 4 行的過程體的第一個可執行語句，這時的狀況是：

```
[S1] ← (X1) ← (P1) ← PSC
```

這裡方括號表示系統頭領，圓括號表示其他塊實例，左向箭頭表示系附。執行第 4 行的 `detach` 語句後，儲存物件 `X1` 的重新啟用點為第 4 行過程結束，回溯到第 23 行結束，系統 `S1` 的物件 `X1` 生成完畢，這時的情況是：

```
[S1] ← PSC
 |
(X1) ← (P1) ← X1重新激活点
```

這裡的豎槓連接一個系統的組件頭領。PSC 到達系統 `S1` 主幹組件第 24 行，開始生成物件 `X2`，進入類 `C2`，PSC 到達第 13 行的類主體的第一個可執行語句，進入這個子塊產生系統 `S2` 的系統頭領，PSC 到達第 19 行的系統 `S2` 主幹組件的第一個可執行語句，開始生成物件 `X3`，進入類 `C3`，PSC 到達第 16 行類主體的第一個可執行語句，這時的情況是：

```
[S1] ← (X2) ← [S2] ← (X3) ← PSC
 |
(X1) ← (P1) ← X1重新激活点
```

執行第 16 行類主體內的 `detach` 語句後，儲存物件 `X3` 的重新啟用點為第 17 行，回溯到第 19 行結束，系統 `S2` 的物件 `X3` 生成完畢，這時的情況是：

```
[S1] ← (X2) ← [S2] ← PSC
 |             |
 |            (X3) ← X3重新激活点
 |
(X1) ← (P1) ← X1重新激活点
```

PSC 到達系統 `S2` 主幹組件的第 20 行，執行 `resume(X3)` 語句後，儲存系統 `S2` 主幹組件的重新啟用點為第 21 行，PSC 恢復到第 17 行的物件 `X3` 的類主體之中，這時的情況是：

```
[S1] ← (X2) ← [S2] ← S2重新激活点
 |             |
 |            (X3) ← PSC
 |
(X1) ← (P1) ← X1重新激活点
```

執行第 17 行的類 `C2` 的特性過程 `P2`，到達在第 10 行的過程體的第一個可執行語句，這時的情況如下，並標記為「狀況 A」：

```
                                   ! 状况A
[S1] ← (X2) ← [S2] ← S2重新激活点
 |             |
 |            (X3) ← (P2) ← PSC
 |
(X1) ← (P1) ← X1重新激活点
```

執行在第 10 行 `P2` 過程體的 `detach` 語句後，儲存物件 `X2` 的重新啟用點為第 11 行，回溯到第 24 行結束，系統 `S1` 的物件 `X2` 生成完畢，這時的情況如下，並標記為「狀況 B」：

```
                                   ！状况B
[S1] ← PSC
 |
(X1) ← (P1) ← X1重新激活点
 |
(X2) ← [S2] ← S2重新激活点
        |
       (X3) ← (P2) ← X2重新激活点
```

注意物件 `X3` 仍是系統 `S2` 的生效組件，它並沒有自己的重新啟用點。PSC 進入系統 `S1` 主幹組件第 25 行，執行 `call(X2)` 後，PSC 恢復為第 11 行的 `P2` 過程體之中，這時的情況重現為前面的「狀況 A」。如果將第 25 行覆寫為一個 `resume(X2)` 語句，執行後儲存系統 `S1` 主幹組件的重新啟用點為第 26 行，PSC 恢復為第 11 行的 `P2` 過程體之中，會出現如下情況：

```
[S1] ← S1重新激活点
 |
(X1) ← (P1) ← X1重新激活点
 |
(X2) ← [S2] ← S2重新激活点
        |
       (X3) ← (P2) ← PSC
```

如果將第 11 行的注釋替換為一個 `detach` 語句，執行後儲存物件 `X2` 的重新啟用點是第 12 行，PSC 恢復到第 26 行的系統 `S1` 主幹組件之中，這時的情況重現為前面的「狀況 B」。如果將第 11 行的注釋替換為一個 `resume(X1)` 語句，執行後儲存物件 `X2` 的重新啟用點為第 12 行，PSC 恢復到第 4 行的 `P1` 過程體的過程結束，會出現如下情況：

```
[S1] ← S1重新激活点
 |
(X1) ← (P1) ← PSC
 |
(X2) ← [S2] ← S2重新激活点
        |
       (X3) ← (P2) ← X2重新激活点
```

### 二元樹

下面例子中的 `Tree` 類，是二元樹資料結構實現：

在 `find` 的過程體中出現了表達式 `this Tree`，它意圖產生的值是到當前節點的參照，就是說這個節點擁有 `find` 特性的「這個」特定實例。例如，如果通過函式指示符 `X.find (x)`，來呼叫 `X` 的 `find` 過程，並且 `X.val = x`，則這個函式的結果是 `X` 自身的參照值。

### 抽象類

下面例子中，定義了一個抽象基礎類：字形類 `Glyph`，它有二個實現子類：字元類 `Char` 和行類 `Line`：

這裡的虛過程量 `print` 具有過程規定 `Is Procedure print`，它匹配既沒有形式參數也沒有返回值的 `print` 過程，如果不加以這種過程規定，則它可以匹配具有任何形式參數和任何返回值的 `print` 過程。在 Simula 67 中，沒有不可以實例化帶有純虛過程類的特定限制，因而缺乏真正的抽象類的概念，所有類都可以被實例化，但是呼叫純虛過程會產生執行時間錯誤。

### 模擬器

在下面的離散事件類比例子中，Sam、Sally 和 Andy 正在逛商店買衣服，他們必須共享一個試衣間。他們每人只能瀏覽商店大約 12 分鐘，並接著獨占的使用試衣間大約 3 分鐘，每個活動都服從常態分布，他們的試衣間經歷被類比如下：

主程式是字首著模擬器類 `Simulation` 的有字首塊。模擬器類可在任何塊上使用，而且模擬器甚至可以巢狀，比如在類比某人做類比的時候。啟用語句 `Activate`，只在包括在 `Simulation` 中的類的物件之中，或在其字首部份是這種物件的有字首塊之中，才是有效的。啟用語句的作用，被定義為呼叫 `ACTIVAT` 過程所得到效果。`ACTIVAT` 過程和等待過程 `Wait`，定義在行程類 `Process` 中，而 `Process` 類是 `Simulation` 類的內部類。

表示集合整體的 `Head` 類，和表示集合元素的 `Link` 類，都是集合類 `Simset` 的內部類；而 `Simset` 類，是 `Simulation` 類別宣告中的字首。首位過程 `First`，定義在 `Head` 類中；登出過程 `Out` 和在 `Wait` 過程中用到的進入過程 `Into`，定義在 `Link` 類中。

物件 `fittingRoom1` 是試衣間類 `FittingRoom` 的實例，為了讓人們排隊等待存取試衣間，它使用了一個佇列實例即門物件 `door`。當某人要求用試衣間的時候，如果它正在由他人使用，則必須等待於它的門佇列之中，即 `Wait (door)`，當經過排隊後得以使用試衣間的時候，相應的從它的門佇列中移除自己，即 `door.First.Out`。當某人離開試衣間的時候，在它的門佇列中有人的情況下釋放出第一個人，即 `Activate door.First`。

個人類 `Person` 是 `Process` 類的子類，而它的活動，即用來瀏覽商店的時間，和在試衣間度過的時間，使用 `Process` 類的保持過程 `Hold` 來描述，並呼叫在試衣間物件中的過程，來要求和離開試衣間。常態分布的隨機抽籤過程 `Normal`，定義在 `ENVIRONMENT` 類中，它的最後的參數，必須是指定一個偽亂數串流的一個整數。主程式建立所有物件，並啟用所有 `Person` 物件，從而將他們放置入事件佇列之中。主程式在程式終止前，保持 100 分鐘的類比時間。

## 參見

* 物件導向程式設計

## 注釋

## 延伸閱讀

* Sylvester, Peter. IBM System 360/370 Compiler and Historical Documentation (The Simula Standard and other historical documentation). [2020-05-15]. （原始內容存檔於 2019-10-01）.
* Pooley, Rob, An Introduction to Programming in Simula (PDF), Alfred Waller Ltd, 1987 [2022-03-15], ISBN0632016116, （原始內容 (PDF) 存檔於 2022-04-07）

## 外部連結

* GitHub 上的 Portable Simula Revisited
* 重建中的官方網站