Simula
編程範型 | 多範式: 指令式, 程序式, 結構化, 物件導向, 並行 |
---|---|
設計者 | 奧利-約翰·達爾 |
實作者 | 克利斯登·奈加特 |
釋出時間 | 1962年 1967年 (Simula 67) | (Simula I)
目前版本 |
|
型態系統 | 靜態、名稱式 |
作用域 | 詞法 |
實作語言 | 主要為ALGOL 60(有一些Simscript成份) |
作業系統 | 類Unix系統、Windows、z/OS、TOPS-10、MVS |
主要實作產品 | |
Portable Simula Revisited[2], GNU Cim[3] | |
啟發語言 | |
ALGOL 60, Simscript[4] | |
影響語言 | |
Smalltalk[5]、CLU[6]、C++、BETA、Object Pascal、Modula-3、Java |
Simula,一種編譯式的程式語言,由奧利-約翰·達爾與克利斯登·奈加特,在1960年代於挪威奧斯陸的挪威計算中心,開發出來了Simula I與Simula 67兩代。它承繼了ALGOL 60作為基礎,被認為是第一個物件導向程式設計的程式語言。
Simula 67介入了對象、類、子類(後來慣稱為子類繼承超類)、虛過程[8],還有協程、離散事件模擬和特徵性的垃圾收集[9]。Simula的影響經常被低估[10],Smalltalk[5]、CLU[6]、C++、Object Pascal、Modula-3、Java和後來的很多程式語言,受到了Simula 67的啟發。BETA是Simula的現代後繼者。
歷史
[編輯]1957年,克利斯登·奈加特開始在NDRE的Ferranti Mercury電腦上寫模擬器,為此他需要更強大的程式語言。1962年1月,奧利-約翰·達爾開始跟他合作,他們受到ALGOL 60的啟發。1962年5月,發展出第一份模擬器程式語言提議,語言取名為SIMULA,後改稱為Simula I。此時,克利斯登·奈加特受到Sperry Rand公司邀請,去協助他們開發UNIVAC 1107電腦。UNIVAC軟件部門的主管鮑伯·貝莫,力邀克利斯登·奈加特前往國際資訊處理協會(IFIP)舉行的第二次國際會議上,發表了論文「SIMULA-擴展ALGOL到離散事件網絡的描述」[11]。
1963年8月,挪威計算中心(NCC)購買到UNIVAC 1107,在UNIVAC的合約同意下,奧利-約翰·達爾在這台電腦上安裝以凱斯西儲 1107 ALGOL 60的編譯器來實作的Simula I。1965年1月,Simula I終於可以在UNIVAC 1107上完全的運作。Simula I在1968年被移植到了Burroughs B5500電腦,以及後來蘇聯的URAL-16電腦。
1965年,東尼·霍爾首次提出「記錄類」(record class)構造的概念[12],1966年,克利斯登·奈加特與奧利-約翰·達爾二人,將Simula I的具有「准並列」性質的「進程」,擴展成了具有了記錄類性質的廣義進程,隨即改稱為「物件」[13]。1967年5月,奈加特和達爾在奧斯陸舉辦的IFIP工作小組討論區中,發表了關於類與子類聲明的論文,形成Simula 67的第一份定義檔案[14]。
1968年召開的會議,組成了SIMULA標準小組,並發表了第一份官方Simula標準檔案「SIMULA 67通用基礎語言」[15]。在1960年代後期和1970年代早期,Simula 67主要實現於四個系統之上:挪威計算中心的UNIVAC 1100系列,挪威計算中心的IBM System/360和System/370,奧斯陸大學在Kjeller聯合安裝的CDC 3000系列,和瑞典國防研究所(FOA)的DEC TOPS-10。
當前的Simula 67業界標準,是在1986年修訂的「標準SIMULA」[7],它在1987年被接受為瑞典國家標準[16]。它有四個主要實現:Simula AS、Lund Simula、GNU Cim[3]和Portable Simula Revisited[2]。
Simula影響了Smalltalk[5],和後來的物件導向程式設計語言[10]。C++語言和Java語言的創始人,都認可自己受到了Simula的重要影響[17]。
語法和語意
[編輯]Simula 67包含通用演算法語言ALGOL 60的多數特徵作為自己的子集[7],它是大小寫不敏感的。Simula 67的中心概念是對象,對象是自我容納(self-contained)的一段程式即一個塊實例,它擁有由一個類聲明定義的自己的局部數據和行動(action)。類是一種過程[18],它有能力引起在它被呼叫後仍存活的一個塊實例,而這些實例就叫做這個類的對象。為了操縱對象和相互關聯對象,語言介入了鏈結串列處理設施。
Simula 67為了將整個程式執行組織為:對象所屬的諸「行動階段」的一個序列,而將其所必需的基本功能特徵,包含在作為「系統類」的「環境類」之中。在環境類中有被稱為「標準系統類」的模擬器類Simulation
,它定義了充當系統時間軸的「定序集合」(sequencing set)對象SQS
、行程類Process
和事件通告類EVENT_NOTICE
,定序集合的成員是事件通告對象,它通過其PROC
特性提及一個行程對象;事件通告表示了對應這個行程對象的下一個行動階段的一個事件,被排程在系統時間EVTIME
時發生。
塊
[編輯]塊是成序列的聲明,跟隨着成序列的陳述式,並被包圍在關鍵字begin
和end
之間。塊自身是一種陳述式[19],在Simula 67中,它包括子塊和有字首(prefixed)塊,在語法上,子塊就是無字首的ALGOL 60的塊,即匿名塊和過程主體。
聲明擔負定義在程式中用到的量(quantity)的特定屬性,並給它們關聯上識別碼,這包括:簡單變數、陣列、switch
(標籤列表)、過程、類和外來聲明。塊中的每個陳述式,都可以是塊或複合陳述式。複合陳述式與塊相比在語法上沒有聲明。
所有的塊,自動地介入名稱目錄(nomenclature)的一個新的層級:在這個塊內出現的識別碼,可以通過合適的聲明,而被指定為局部於所論及的這個塊;這個識別碼在這個塊裏面的所表示的實體,不存在於它的外面;這個識別碼在這個塊外面的所表示的任何實體,在這個塊裏面是不可見的;在Simula 67中,可通過連接或遠端訪問使它成為可見的。
除了表示標籤的識別碼之外,一個識別碼,如果出現在一個塊中,而且並非聲明於這個塊中,則它非局部於這個塊。因為塊中的陳述式自身可以是一個塊,局部和非局部於一個塊的概念,必須遞歸地去理解。
塊是一種形式描述或模式,關乎匯聚的數據結構和關聯的演算法以及行動[20]。當一個塊執行的時候,生成這個塊的一個動態實例[21]。一個塊實例,可以被認為是它的形式描述的文字複本。在電腦中,一個塊實例可以採用某一種形式的主記憶體區域,它包含需要的動態塊資訊,並包括空間來持有局部於這個塊的變數的內容[22]。
塊的任何一個內部的塊,仍然是一個模式,但是在其中出現的非局部識別碼,標定了局部於在字面上外在包圍(textually enclosing)的塊實例的專案[23]。非局部於內部的塊的識別碼繫結,對這個內部的塊的任何隨後的動態實例,保持有效[24]。
塊實例中的局部變數,標識了分配給塊實例的主記憶體片段。在進入一個塊之中的時候,任何局部於這個塊即在其中聲明的變數,都會被初始化。局部於一個塊的一個變數,是一個主記憶體裝置,其內容依據這個變數的類型,要麼是一個值,要麼是一個參照。
值類型可特徵化為直接關聯着一個可能值的集合,即這個類型的「值範圍」。參照概念,對應於一個名字或一個「指標」的直觀想法。在Simula 67中有兩種參照類型,對象參照類型和文字參照。對於值類型不關聯着參照概念。提供了參照值的機制,還反映了機器的定址可能性;在特定簡單情況下,一個參照可以被實現為一個儲存的值的主記憶體地址。
過程
[編輯]過程與塊相比,它有一個名字,可以在程式的一些不同地方提及,並且在呼叫時可以給出參數[25]。過程和塊都不可能建立到它或它內部的參照[25];對於一個給定塊,有可能生成它的一些可以共存和互動的實例[22],例如遞歸過程的實例。
過程的參數傳送模態,除了有傳值呼叫和傳名呼叫[26],在Simula 67中,又增加了傳參照呼叫。過程的預設的傳送模態,在Simula 67中,對於值類型的參數是傳值呼叫,對於所有其他類型的參數是傳參照呼叫;故而在過程聲明的參數規定中,增加了以name
為前導的名字部份,用來指定所述及的參數採用傳名呼叫。
在過程主體內傳名呼叫的形式參數的每次出現,都引起對實際參數的一次求值。在Simula 67中,這個求值發生在過程陳述式的上下文中,就是說不會出現識別碼衝突,因為過程主體和它的變數此時是不可見的。過程呼叫的執行,在有參數的情況下要經歷如下步驟:建立形式參數塊實例;求值對應於傳值呼叫或傳參照呼叫的實際參數,並將其結果賦值給形式參數塊實例的對應變數;過程主體被初始化並開始執行。
真正(proper)過程,不定義特定類型的函數指定式的值,在Simula 67中,它被稱為具有普遍(universal)類型,任何類型都從屬(subordinate)於普遍類型。
類與對象
[編輯]類別宣告定義一個程式(數據和行動)模式,而符合(conforming)這個模式的對象被稱為「屬於相同的類」。不同於Smalltalk 80等物件導向程式設計語言,Simula 67的類和後來的Modula-3的對象類型,不進行實例變數與類別變數的區分。
對於一個給定對象,類別宣告中形式參數、在虛擬部份中規定的虛擬量,和聲明為局部於類主體(body)的量,叫做這個對象的特性(attribute)。一個特性的聲明或規定叫做特性定義。在1986年修訂的語言標準中,通過保護規定可以限制類特性識別碼的可見性。
類別宣告中的形式參數,不適用傳名呼叫,這是為了保證實際參數在類所引起的對象存活期間不能消失[27]。在規定部份中需要對每個形式參數進行規定,這些參數被當作局部於類主體的變數。類主體通常是一個塊,即使它如語法形式所允許的那樣是塊以外的一個陳述式,也表現得如同一個塊。一個分裂(split)主體表現為一個塊,在其中符號inner
表示一個虛設(dummy)陳述式。
Simula 67的類主體中除了有定義特性的聲明,還可以有定義行動的陳述式。如果在一個類別宣告中有行動定義,則符合這個模式的行動,可以由屬於這個類的所有對象執行。如果在類別宣告中沒有指定行動,則定義了一類純數據結構,很多後來的物件導向程式設計語言就是這樣,將對象作為記錄或結構的擴充。例如:
class Order(number); integer number;
begin
integer numberOfUnits, arrivalDate;
real processingTime;
end;
屬於特定類的對象,通過對象表達式中的對象生成式new
來生成,並製作出到它的參照。例如,想要多少就能生成多少屬於這個Order
類的一個新對象:
new Order(103);
屬於一個對象的行動,可以都在就一個過程而言的一個序列中執行。這些行動,還可以作為一系列的獨立子序列或「行動階段」(active phase)來執行。在一個給定對象的兩個行動階段之間,可以出現任何數目的其他對象的行動階段。
子類與類串接
[編輯]一個類可以被用作到另一個類別宣告的「字首」,從而將字首所定義的性質,建造入這個新的類別宣告定義的對象之中。具有字首類C
和類識別碼D
的一個類別宣告,定義了類C
的一個子類D
。屬於子類D
的對象,由自身是類C
的對象的「字首部份」,和類D
的類別宣告主體所描述的「主體部份」組成。這兩部份串接而形成了一個複合對象,它可以用串接成的類別宣告來正式的描述,串接的過程被認為先於程式執行而發生。
類只能在定義它的塊層級中用作字首。字首類自身也可以有字首。類不能出現在自己的字首序列中。子類被稱為內部(inner)於字首類,而字首類被稱為外部(outer)於子類,但不可將子類稱為字首類的內部類。這不同於後來的物件導向程式設計語言中的稱謂:「衍生類別」擴充「基礎類」,或「子類」繼承「超類」。例如:
Order class SingleOrder;
begin
real setupTime, finishingTime, weight;
end;
SingleOrder class Plate;
begin
real length, width;
end;
屬於Order
類的子類如SingleOrder
類和Plate
類的新對象,都含有Order
類別定義的數據,再加上在各種類別宣告中定義的補充數據。例如,屬於Plate
類的對象含有Order
類、SingleOrder
類和Plate
類別定義的所有數據。
一個識別碼在一個塊中的出現,如果並未處在遠端識別碼之中或在有重新定義的內部的塊之中,則被稱為「未託付」(uncommitted)出現。對於子類的聲明及其字首類串接成的類別宣告,在局部於子類的特性識別碼,和局部於其字首類的特性識別碼,二者的未託付出現之間的可能衝突,將憑藉對涉及到的局部於子類的特性識別碼的適合的系統性變更來避免,但是對應虛擬量的識別碼不變更。
對於字首類和子類別宣告串接成的類別宣告,它的形式參數列,由字首類的形式參數列,和附加的子類別宣告的參數列二者合併而成。它的值部份、規定部份和虛擬部份,是字首類和子類別宣告相應各部份的併集。結果的虛擬部份不能包含某個識別碼的多於一次出現。
對於類主體,最初的begin
和隨後的聲明被稱為「塊頭部」,從第一個可執行陳述式直到inner
之前的陳述式被稱為「初始運算」,在inner
之後的陳述式和最終的end
被稱為「複合尾部」。如果字首類主體是分裂主體,用字首類的塊頭部複本替代子類的塊頭部中的begin
,將字首類的初始運算複本插入到子類的塊頭部之後,用字首類的複合尾部複本替代子類的複合尾部中的end
。如果字首類主體不是分裂主體,它被解釋為如同將;inner
插入到最終的end
之前。
設Cn
是具有字首序列C1, C2, ……, Cn-1
的一個類,這裏類Ck
(k = 1, 2, ……, n)
的下標k
叫做字首層級,X
是屬於類Cn
的一個對象,則X
是一個複合對象;非正式的說,串接機制有如下結果:
- 對象
X
擁有的特性集合,是在序列C1, C2, ……, Cn
中諸類所定義特性集合的併集。在類Ck
(1 <= k <= n)
中定義的特性,被稱為定義在字首層級k
。 - 對象
X
擁有的「運算規則」,由來自這些類主體的諸陳述式構成,它們所屬的字首層級遵循規定的次序。來自類Ck
的陳述式,被稱為屬於對象X
的字首層級k
。 - 在對象
X
的字首層級k
的陳述式,能訪問在對象X
的等於或外部於k
的字首層級上定義的它的所有特性,但是如果外部的類Ci
(i < k)
中存在衝突定義,則導致對應特性不可見而不能直接訪問。這些不可見特性仍有訪問方式,例如通過使用過程或this Ci
。 - 在對象
X
的字首層級k
的陳述式,不能立即訪問在對象X
的內部於k
的字首層級上定義的它的那些特性,除非通過虛擬量。 - 在字首層級
k
的分裂主體中,符號inner
,表示對象X
的屬於內部於k
的字首層級的運算規則的諸陳述式,或者在k = n
時表示虛設陳述式。如果序列C1, ……, Cn-1
都沒有分裂主體,則在對象X
的運算規則中諸陳述式所屬的字首層級遵循遞增次序。
用作字首的系統類,與其字首鏈的所有的類一起,被當作聲明於最小的包圍其字面上出現的塊中。因此重新聲明可以出現在一個程式的內部的塊層級中。
有字首塊的一個實例,是由塊字首生成的一個單一的對象,與這個主體塊的實例,串接而成一個複合對象,其串接定義採用類似於類的串接規則。塊字首的類的形式參數,按塊字首的實際參數所示初始化。對有字首塊有兩個限制:一個類如果在其中通過使用this
來參照類自身,則它作為塊字首是非法的。塊字首的類識別碼所提及的類,必須局部於最小的包圍這個有字首塊的塊。
對象參照
[編輯]當屬於各種類的很多對象,作為同一個程式的各個部份而共存的時候,需要能夠對個體對象指定名字,為此介入了叫做「參照」的新的基本類型;還要能相互關聯對象,比如通過二叉樹和各種其他類型的列表結構。Simula 67將迴圈雙向鏈結串列叫做「集合」,它將集合類Simset
作為「標準系統類」介入為環境類的一部份。
對於某個類的一個對象,有一個唯一的關聯的「對象參照」標定這個對象,並且對於任何類C
,都有一個關聯的對象參照類型ref(C)
。這種類型的量,被稱為由類C
限定;它的值,要麼是一個對象,要麼是表示「沒有對象」的特殊值none
。
限定(qualification)將值的範圍,限制至包括在限定類中的這些類的對象。不管何種限定,值的範圍都包括值none
。一個對象參照的限定,是一個類識別碼,它因此服從聲明的作用域和可見性規則。限定關聯於所提及的類別宣告所局部於的那個塊的一個實例。這蘊涵着特定的關於限定有效性的檢查,不能單獨在程式正文的基礎上進行,因此這種測試必須在程式執行期間完成。
參照是有限定的,蘊涵着一個給定參照所提及的對象,只能屬於這個限定中提到的類,或屬於這個限定類的子類。如果一個對象參照類型的限定,是另一個對象參照類型的限定類的子類,則前者被稱為從屬於後者。例如:
ref(Order) next, previous;
對象表達式是獲得對一個對象的參照的一種規則。對象表達式的值,是被參照的對象或none
。運算子:-
讀作「指稱」(denote),它指示將一個參照,指派(assign)到處在「參照指派符」左側的參照類型的變數或過程識別碼。例如:
next :- new Plate(50); previous :- next; next :- none;
而運算子:=
讀作「成為」(become),指示將一個值,指派到處在賦值符左側的值類型的變數或過程識別碼,或者將一個文字值,指派到在賦值符左側者所參照的那個文字幀(frame)。
遠端訪問
[編輯]一個對象的一個特定特性,由下列三項資訊來完全標定(identify):
對於任何特性標定,第二項類資訊都是在字面上定義的,從而形成靜態繫結[28]。屬於其他對象的特性,可以要麼單個的通過「遠端識別碼」(「點表示法」),要麼成組的通過「連接」(connection)機制,從其外面「遠端訪問」來參照和使用。
遠端識別碼的形式為:简单对象表示式.特性标识符
,它可用作簡單變數、陣列變數、函數指定式(designator)和過程陳述式中的識別碼,這種點表示法給出對資訊的單獨片段的訪問,例如:
if next.number >= previous.number then ……;
它將名為next
的類Order
的對象的特性number
,比較於名為previous
的類Order
的對象的特性number
。
「成組訪問」可通過連接陳述式inspect
來完成,例如:
inspect next when Plate do begin …… end; inspect new Plate(50) do begin …… end;
在這裏的begin
和end
之間的陳述式中,next
參照的對象所屬的Plate
類的所有資訊片段,都可以直接提及。
在do
後面的陳述式,如果是塊以外的一個陳述式,它表現得也如同一個塊。連接陳述式進而表現得如同被叫做「連接塊」的第二個虛構(fictitious)的塊所包圍。連接機制的用途,是為在連接塊中的特定特性標定,提供對象資訊和在when
子句中的類資訊的隱式定義。
設對象表達式求值為X
,在連接塊執行期間,稱對象X
為「被連接上」了。連接塊有一個關聯的「塊限定」,如果連接塊有when
子句,它是前面的類識別碼,如果沒有when
子句,它是前面的對象表達式的限定。
虛過程
[編輯]虛擬(virtual)量,是在類別宣告中由virtual:
前導的量,它有雙重用途:
- 允許在一個對象的一個字首層級上,訪問在內部字首層級上聲明的特性。
- 允許在一個字首層級上的特性重新定義,在外部字首層級上有效。
不同於一般的特性標定,虛過程形成「半動態繫結」[8],在某種意義上是類似傳名呼叫的機制[27]。這種機制不同於Smalltalk 80等物件導向程式設計語言中,上溯子類至超類的繼承鏈來找到最近的方法實現的那種動態繫結。
一個對象的一個虛擬量,要麼是「無匹配的」的,要麼被標定為具有一個「匹配」特性,它是在這個虛擬量的字首層級上或在內部字首層級上聲明的,其識別碼重合(coincide)於虛擬量的識別碼的一個特性。匹配特性必須與虛擬特性有相同的種類。在一個給定字首層級上的匹配量的類型,必須重合或從屬於這個虛擬規定的類型,和在任何外部字首層級上聲明的任何匹配量的類型。
在1986年修訂的語言標準中,虛過程量可選的可使用procedure <过程标识符> <过程规定>
方式來指定,即憑藉它的類型,並且如果它有形式參數,則還憑藉它們的類型、種類和傳送模態。含有過程規定is <过程声明>
的虛過程量,只能由有相同類型的過程來匹配,並它與這個過程規定具有相同的過程頭部。
例如,下面實現雜湊表的HashTable
類,聲明了整數類型的虛過程hash
並隨即實現了它,又定義了要用到這個雜湊函數hash
的尋找過程lookup
:
class HashTable(n); integer n;
virtual: integer procedure hash;
begin
integer procedure hash(t); text t;
begin
……
end hash;
text array table(0 : n-1); ……
integer procedure lookup(t, old);
name old; Boolean old; text t;
begin
integer i, istart; Boolean entered;
i := istart := hash(t);
while not entered do
begin
……
end;
lookup := i;
end lookup;
end HashTable;
HashTable class ALGOL_hashing;
begin
integer procedure hash(t); text t;
begin
……
end hash;
end ALGOL_hashing;
作為子類的ALGOL_hashing
類和以HashTable
類為字首的有字首塊,可以用自己的hash
過程實現,替代在HashTable
類中的實現。在子類的類主體和有字首塊的主體塊中,能獲得到過程lookup
,而它用到的過程hash
是這裏提供的替代實現。
對象表達式
[編輯]對象表達式,具有類型ref(限定)
。對象表達式的限定規則包括:對象生成式(generator)、局部對象或限定對象,分別由跟隨符號new
、this
或qua
的識別碼的類來限定(qualification)。
對象生成式new C
,這裏標定了類C
,它涉及到屬於類C
的對象的生成和執行。這個對象是類C
的一個新實例。對象生成式的求值構成自如下行動:
- 生成這個對象,並且如果這個對象生成式有實際參數,則求值它們,將得到的這些值及或參照傳送給形式參數。
- 控制經過這個對象最初的
begin
進入其中,它籍此變成在「系附」狀態下執行。當所生成的對象執行了detach
基本過程變為「脫離」狀態,或者經過這個對象最終的end
退出而變為「終止」狀態,對象生成式的求值完成。
局部對象this C
,這裏的C
是類識別碼。如果用在類C
或C
的任何子類的類主體中,或用在其塊限定為類C
或C
的一個子類的連接塊中,則這個對象表達式是有效的。在一個給定的上下文中,一個局部對象的值,是一個對象或連接到一個對象,它是這個對象表達式在其中有效的、最小的在字面上外在包圍的塊實例;如果沒有這樣的塊,則這個對象表達式在這個上下文中是非法的。對於一個過程或類主體的實例(上下文),「在字面上外在包圍」(textually enclosing)意為包含它的聲明。
暫瞬限定X qua C
,這裏的X
表示一個簡單的參照表達式,而C
是類識別碼。設類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
的值的否定。
作用域和可見性
[編輯]不同於ALGOL 60規定了量的作用域與可見性,在Simula 67中,一個識別碼定義及其關聯的識別碼,在其作用域與可見性之間需要做出區別。
- 作用域:一個識別碼定義的作用域,是它在其中可能有作用的那一部份程式正文。同一個識別碼,可以定義在程式的很多地方,因此可以關聯於不同的量。同一個識別碼的這些定義的作用域,因而可能有所重疊,例如在一個識別碼在內部塊中被重新聲明的情況下。
- 可見性:一個識別碼定義,如果它所關聯的識別碼,在程式的給定點上能夠提及到這個定義所聲明的量,則它被稱為在這個點上是可見的。在給定識別碼於此可見的程式正文的一個特定點上,最多只能有一個定義關聯於這個識別碼,例如在重新聲明的情況下,在它們作用域的併集內任何給定點上,只有一個定義是可見的。
一個識別碼定義的局部塊,是在字面上最近的包圍塊,即子塊、字首塊、過程主體或類主體,還包括圍繞for
陳述式的受控陳述式、過程聲明、類別宣告和連接塊等的虛構塊。這個識別碼和它的定義,被稱為局部於這個塊。
識別碼定義,只在它們的作用域內是可見的。一個特定定義的可見性,在它的作用域內可以受到下列限制:
- 在一個識別碼定義的局部塊所包圍的某個構造內,出現的具有相同識別碼的識別碼定義,是這個識別碼的重新定義。在它們共同的作用域內,只有最內部的重新定義是可見的。
- 一個重新定義,出現在類的某個內部字首層級。
- 遠端訪問,可以導致某些識別碼定義在檢視塊或點表示法內變成不可見的。
- 使用
this
或qua
,可以導致一個或多個重新定義被暫時停止。 - 在這個識別碼定義所局部於的類別宣告中,這個識別碼出現在由
hidden
及或protected
前導的保護部份中。
一個識別碼的重新定義,不允許出現在它的局部塊的頭部,這禁止了在同一個塊中出現相同識別碼的兩個定義。
塊實例
[編輯]一個程式執行的各個組成部份,都是塊即子塊、有字首塊、連接塊和類主體的動態實例。一個塊實例,被稱為「局部於」直接包含它的描述正文的那個塊實例。例如一個給定類別的實例,局部於包含這個類別宣告的塊實例。最外層塊的實例不局部於塊實例。
在任何時間,「程式順序控制」(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最初標準中曾提到過,語言實現可以使用垃圾回收技術[9],來進一步縮減一個對象的有效壽命的跨度。一個陣列聲明的動態作用域,可以擴充超出包含這個聲明的塊實例的作用域,因為傳參照呼叫參數傳送模態適用於陣列。
准並列系統
[編輯]一個準並列系統[29],由「構件」(component)構成。構件是塊實例組成的巢狀結構,其中標定(identify)這個構件的那個塊實例,叫做「構件頭領」。在每個系統中,構件中總是有一個被稱呼為「主構件」,在Simula 67最初標準中它叫做「主程式」,其他構件叫做「對象構件」。
構件的定序(sequencing),由detach
、call
和resume
過程支配。detach
過程針對隱式指定的一個對象進行操作,而call
和resume
過程顯式指定所操作的對象。
一個準並列系統,由包含局部的類別宣告的一個子塊或有字首塊的任何實例所標定。標定了一個系統的塊實例,叫做「系統頭領」。一個系統的主構件的頭領(head),重合(coincide)於系統頭領。最外層的標定了一個系統的塊實例,被稱為「最外層系統」。
一個系統的主構件的頭領,總是處在系附狀態。一個系統的對象構件的頭領,確切的就是局部於系統頭領的那些脫離狀態的或恢復狀態的對象。在任何時間,在一個系統的構件之中,有確切的一個構件被稱為「生效」(operative)的。不生效的構件,有關聯的「重新啟用點」,它標定在這個構件被啟用(activate)時,要在它那裏繼續執行的程式點。一個對象構件是生效的,若且唯若這個構件的頭領處在恢復狀態。
稱謂一個塊實例P
被一個塊實例X
「動態包圍」,若且唯若存在一個塊實例序列:(P = Z0), Z1, ……, Zn-1, (Zn = X)
(n >= 0)
,使得對於i = 1, 2, ……, n
有着:Zi-1
系附到Zi
;或者Zi-1
是一個恢復狀態的對象,它關聯的系統頭領系附到Zi
。終止狀態和脫離狀態的對象,不被除了自身之外的塊實例動態包圍。
將當前包含PSC的塊實例動態包圍起來的塊實例鏈,叫做「執行鏈」。在執行鏈上的塊實例,被稱為是「執行」(operating)的,最外層的塊實例總是執行的。一個構件只要其頭領是執行的它就是執行的。
一個系統如果有一個構件是執行的,它就是執行的;在任何時間,一個系統最多有一個構件是執行的;執行的系統的頭領,可以是不執行的。一個執行的構件總是生效的;如果一個系統的生效構件是不執行的,則這個系統也是不執行的。在不執行的系統中的生效的構件,是當這個系統成為不執行的時候在執行的構件,當這個系統再次成為執行的時候它將仍是執行的。
對於一個不生效的構件C
,設它的頭領是X
,如果一個塊實例P
包含了它的重新啟用點,則P
被X
動態包圍,並且P
除了自身之外不動態包圍塊實例。由構件頭領X
動態包圍的這個塊實例序列,被稱為構件C
的「重新啟用鏈」。除了X
之外,這個鏈上的所有構件頭領,標定了生效而不執行的構件。在構件C
成為執行的時候,在它的重新啟用鏈上所有塊也成為執行的。
除了系統構件,程式執行還可以包含不屬於特定系統的「獨立對象構件」。任何這種構件的頭領,都是一個脫離狀態的對象,它局部於一個類對象或一個過程主體實例,也就是說不局部於某個系統頭領。根據定義,獨立構件總是不生效的,只能對它執行call
過程。
協程和生成器
[編輯]准並列系統的detach
/resume
機制,是一種協程[30]。在Simula 67最初標準中,沒有恢復狀態,並且沒有規定call
過程,但call
過程通常會出現在當時的語言實現中[31]。detach
/call
機制,相當於現在稱為生成器的「半協程」,而最初標準中的resume
過程可理解為detach
過程與call
過程的組合[32]。1986年修訂的語言標準,增補定義了call
過程,新增了恢復狀態,並且重新定義了resume
過程,它不可再理解為detach
過程與call
過程的組合。
准並列系統,被建立於進入包含局部的類別宣告的一個子塊或有字首塊的時候,藉此生成的實例成為這個新系統的頭領。初始時,這個主構件是生效的,並且是這個系統唯一的構件。
建立一個對象構件,要通過針對一個系附狀態的對象,執行detach
過程,藉此PSC返回到這個對象系附到的那個塊實例。這個對象進入脫離狀態,並成為一個新的不生效的構件的頭領,這個構件的重新啟用點被定位到緊後於這個detach
過程呼叫。如果這個對象局部於一個系統頭領,則這個新的構件成為這個關聯的系統的成員。
通過detach
和call
過程,可以形成「半對稱定序」,這隻涉及到對象構件,而不區分它們是屬於系統的構件還是獨立的構件。
- 對於一個不生效的對象構件,通過針對它的脫離狀態的頭領,執行一個
call
過程,可以重新啟用這個構件,藉此PSC移動到它的重新啟用點上。這個頭領重新進入系附狀態,並變成系附到包含這個call
過程呼叫的塊實例上。這個構件正式的失去了本身(作為構件)的狀態。
通過detach
和resume
過程,可以形成「對稱構件定序」,這隻涉及到屬於一個準並列系統的那些構件。對立於半對稱定序中的「呼叫者」與它的「被呼叫者」,在對稱構件定序中的「恢復者」與它的「被恢復者」,具有完全的對稱聯絡。
- 對於這個系統的一個不生效的對象構件,通過針對它的脫離狀態的頭領,執行一個
resume
過程,可以重新啟用這個構件,藉此PSC移動到它的重新啟用點上;這個構件的頭領進入恢復狀態,而這個構件變成生效的。這個系統以前生效的構件變成不生效的,並且它重新啟用點被定位到緊後於這個resume
過程呼叫;如果這個構件是一個對象構件,則它的頭領進入脫離狀態。 - 對於當前生效的對象構件,通過針它的恢復狀態的頭領,執行一個
detach
過程呼叫,這個系統的主構件重獲生效的狀態,藉此PSC移動回到主構件的重新啟用點上。以前生效的構件變成不生效的,並且它重新啟用點被定位到緊後於這個detach
過程呼叫。這個構件的頭領進入脫離狀態。
PSC經過一個類對象的最終end
的效果,除了使這個對象成為終止狀態,而非脫離狀態之外,相同於針對這個對象執行detach
過程的效果。其結果是它不會得到重新啟用點,並且在它已經擁有作為構件頭領的狀態時,失去這種狀態。
程式範例
[編輯]Hello, World!
[編輯]Simula 67下的經典Hello, World!範例:
begin
outtext("Hello, World!");
outimage;
end;
outtext
過程將字串輸出到緩衝區,而outimage
過程將緩衝區內容輸出到標準檔案,二者都定義在輸出檔案類OutFile
中,而它是檔案類File
的子類。
二叉樹
[編輯]class Tree(val); integer val;
begin
ref(Tree) left, right;
procedure insert(x); integer x;
begin
if x < val then
begin
if left == none then
left :- new Tree(x)
else
left.insert(x)
end
else if right == none then
right :- new Tree(x)
else
right.insert(x);
end insert;
ref(Tree) procedure find(x); integer x;
begin
if x = val then
this Tree
else if x < val then
(if left == none then
none
else
left.find(x))
else if right == none then
none
else
right.find(x);
end find;
end Tree;
在find
過程的主體中出現了表達式this Tree
,它產生的值所參照的是當前節點。這裏通過函數指定式X.find(x)
,來呼叫對象X
的find
過程,如果X.val = x
,則這個函數的結果是到X
自身的參照值。
協程
[編輯]Simula 67標準通過如下實例來詮釋叫做「准並列系統」的協程機制:
begin comment 系统S1;
ref(C1) X1;
class C1;
begin
procedure P1;
detach;
P1
end C1;
ref(C2) X2;
class C2;
begin
procedure P2;
begin
detach;
! 可尝试detach或resume(X1);
end P2;
begin comment 系统S2;
ref(C3) X3;
class C3;
begin
detach;
P2
end C3;
X3 :- new C3;
resume(X3)
end S2
end C2;
X1 :- new C1;
X2 :- new C2;
call(X2); ! 可尝试resume(X2);
end S1;
這個例子程式中,有兩個准並列系統S1
和S2
。系統S1
是對應最外層子塊的最外層系統,它包含了兩個類別宣告C1
和C2
。系統S2
對應於類C2
的類主體中的匿名塊,它包含了一個類別宣告C3
。
在PSC進入最外層子塊開始處,產生系統S1
的系統頭領,到達第28行的系統S1
主構件的第一個可執行陳述式,開始生成對象X1
,進入類C1
,PSC到達第7行的類主體的第一個可執行陳述式,呼叫了類C1
的特性過程P1
,進入第6行的過程體的第一個可執行陳述式,這時的狀況是:
[S1] ← (X1) ← (P1) ← PSC
這裏方括號表示系統頭領,圓括號表示其他種類的塊實例,左向箭頭表示系附,使用粗體表示這個塊實例執行了對象生成式。執行第6行的detach
陳述式後,對象構件頭領X1
進入脫離狀態,儲存X1
的重新啟用點為第6行P1
過程體結束,回溯到第28行對象產生式結束,系統S1
的對象X1
生成完畢,這時的情況是:
[S1] ← PSC
|
(X1) ← (P1) ← <X1重新激活点>
這裏的豎槓將對象構件頭領列為一個系統的成員。PSC到達系統S1
主構件第29行,開始生成對象X2
,進入類C2
,PSC到達第17行的類主體中匿名塊開始處,進入這個子塊產生系統S2
的系統頭領,PSC到達第24行的系統S2
主構件的第一個可執行陳述式,開始生成對象X3
,進入類C3
,PSC到達第20行類主體開始處,這時的情況是:
[S1] ← (X2) ← [S2] ← (X3) ← PSC
|
(X1) ← (P1) ← <X1重新激活点>
執行第21行類主體的第一個可執行陳述式detach
後,對象構件頭領X3
進入脫離狀態,儲存X3
的重新啟用點為第22行,回溯到第24行對象產生式結束,系統S2
的對象X3
生成完畢,這時的情況是:
[S1] ← (X2) ← [S2] ← PSC
| |
| (X3) ← <X3重新激活点>
|
(X1) ← (P1) ← <X1重新激活点>
PSC到達系統S2
主構件的第25行,執行resume(X3)
陳述式後,儲存系統S2
主構件的重新啟用點為第26行,對象構件頭領X3
進入恢復狀態,PSC恢復到第22行的對象X3
的類主體之中,這時的情況是:
[S1] ← (X2) ← [S2] ← <S2重新激活点>
| |
| (X3) ← PSC
|
(X1) ← (P1) ← <X1重新激活点>
這裏的底線指示這個塊實例處在恢復狀態。執行第22行的類C2
的特性過程P2
,到達在第14行的過程體的第一個可執行陳述式,這時的情況如下,並標記為「狀況A」:
! 状况A ; [S1] ← (X2) ← [S2] ← <S2重新激活点> | | | (X3) ← (P2) ← PSC | (X1) ← (P1) ← <X1重新激活点>
執行在第14行P2
過程體的detach
陳述式後,對象構件頭領X2
進入脫離狀態,儲存X2
的重新啟用點為第15行,回溯到第29行對象產生式結束,系統S1
的對象X2
生成完畢,這時的情況如下,並標記為「狀況B」:
!状况B ; [S1] ← PSC | (X1) ← (P1) ← <X1重新激活点> | (X2) ← [S2] ← <S2重新激活点> | (X3) ← (P2) ← <X2重新激活点>
注意對象X3
仍是系統S2
的生效構件,它並沒有自己的重新啟用點。序列(P2, X3, X2)
是X2
的重新啟用鏈,這裏的X3
是恢復狀態,而它的系統頭領S2
系附到了X2
。
PSC進入系統S1
主構件第30行,執行call(X2)
陳述式後,對象構件頭領X2
進入系附狀態,PSC恢復為第15行的P2
過程體之中,這時的情況重現為前面的「狀況A」(S1
不加粗體)。
如果將系統S1
主構件中第30行覆寫為一個resume(X2)
,執行後對象構件頭領X2
進入恢復狀態,儲存系統S1
主構件的重新啟用點為第31行,PSC恢復為第15行的P2
過程體之中,會出現如下情況:
[S1] ← <S1重新激活点>
|
(X1) ← (P1) ← <X1重新激活点>
|
(X2) ← [S2] ← <S2重新激活点>
|
(X3) ← (P2) ← PSC
序列(P2, X3, X2)
是X2
的執行鏈。
如果將P2
過程體中第15行的註釋替換為一個detach
陳述式,執行後對象構件頭領X2
進入脫離狀態,儲存X2
的重新啟用點是第16行,PSC恢復到第31行的系統S1
主構件之中,這時的情況重現為前面的「狀況B」。
如果將P2
中第15行的註釋替換為一個resume(X1)
陳述式,執行後對象構件頭領X2
進入脫離狀態,對象構件頭領X1
進入恢復狀態,儲存X2
的重新啟用點為第16行,PSC恢復到第6行的P1
過程體的過程結束,會出現如下情況:
[S1] ← <S1重新激活点>
|
(X1) ← (P1) ← PSC
|
(X2) ← [S2] ← <S2重新激活点>
|
(X3) ← (P2) ← <X2重新激活点>
抽象類
[編輯]下面例子中,定義了一個字形類Glyph
,它是抽象基礎類,並且有二個實現子類:字元類Char
和行類Line
:
begin
class Glyph;
virtual: procedure print is procedure print;
begin
end;
Glyph class Char(c);
character c;
begin
procedure print;
outchar(c);
end;
Glyph class Line(cs);
ref(Glyph) array cs;
begin
procedure print;
begin
integer i;
for i := 1 step 1 until upperbound(cs, 1) do
cs(i).print;
outimage;
end;
end;
ref(Glyph) rg;
ref(Glyph) array rgs(1 : 4);
rgs(1) :- new Char('A');
rgs(2) :- new Char('b');
rgs(3) :- new Char('b');
rgs(4) :- new Char('a');
rg :- new Line(rgs);
rg.print;
end;
這裏的虛過程量print
具有過程規定is procedure print
,它匹配既沒有形式參數也沒有結果值的print
過程,如果不加以這種過程規定,則它可以匹配具有任何形式參數和任何結果值的print
過程。在Simula 67中,沒有不可以實例化帶有純虛過程類的特定限制,因而缺乏真正的抽象類的概念,所有類都可以被實例化,但是呼叫純虛過程會產生執行時間錯誤。
模擬器
[編輯]在下面的離散事件模擬例子中,Sam、Sally和Andy正在逛商店買衣服,他們必須共用一個試衣間。他們每人只能瀏覽商店大約12分鐘,並接着獨佔的使用試衣間大約3分鐘,每個行動都服從正態分佈,他們的試衣間經歷被模擬如下:
Simulation
begin
class FittingRoom;
begin
ref(Head) door;
Boolean inUse;
procedure request;
begin
if inUse then
begin
wait(door);
door.first.out;
end;
inUse := true;
end;
procedure leave;
begin
inUse := false;
activate door.first;
end;
door :- new Head;
end;
procedure report(message); text message;
begin
outfix(time, 2, 0);
outtext(": " & message);
outimage;
end;
Process class Person(pname); text pname;
begin
while true do
begin
hold(normal(12, 4, u));
report(pname & " 要求用试衣间");
fittingroom1.request;
report(pname & " 已进入试衣间");
hold(Normal(3, 1, u));
fittingroom1.leave;
report(pname & " 已离开试衣间");
end;
end;
integer u;
ref(FittingRoom) fittingRoom1;
fittingRoom1 :- new FittingRoom;
activate new Person("Sam");
activate new Person("Sally");
activate new Person("Andy");
hold(100);
end;
主程式是字首着模擬器類Simulation
的有字首塊。模擬器類可在任何塊上使用,而且模擬器甚至可以巢狀,比如在模擬某人做模擬的時候[33]。時間過程time
、等待過程wait
、保持過程hold
和啟用過程ACTIVAT
,定義在Simulation
類之中。
行程類Process
是Simulation
類的巢狀類。啟用陳述式activate
,只有處在Simulation
類所包含的類的對象之中,或處在其字首部份是這種對象的有字首塊之中,才是有效的。啟用陳述式的作用,被定義為得到呼叫啟用過程ACTIVAT
的那種效果。
集合類Simset
是Simulation
類的字首類,其中定義了三個巢狀類:表示集合整體的Head
類,表示集合元素的Link
類,和二者的字首類鏈結串列類Linkage
。首位過程first
,定義在Head
類中;退出過程out
和在等待過程wait
中用到的進入過程into
,定義在Link
類中。
在試衣間類FittingRoom
中,為了讓人們排隊等待訪問試衣間,使用了門對象door
,它是佇列類即Head
類的一個對象。試衣間類別定義了兩個過程:要求過程request
:如果試衣間中正有人使用,則他必須等待於門佇列之中,即wait(door)
;當他可以使用試衣間之時,相應的從門佇列中移除自己,即door.first.out
。離開過程leave
:如果門佇列中有人等待的話,放行其中第一個人,即activate door.first
。
個人類Person
是Process
類的子類,它的行動是瀏覽商店和在試衣間試衣,使用保持過程hold
來描述其所用時間,並呼叫對應的試衣間對象的過程來要求和離開試衣間。正態分佈的隨機抽籤過程normal
,定義在環境類ENVIRONMENT
中,它的最後的參數,必須是指定一個偽亂數串流的一個整數。
主程式是行程類Process
的子類MAIN_PROGRAM
類的對象。它建立FittingRoom
類別的實例fittingRoom1
對象,接着建立並啟用Person
類的三個對象,從而將他們三人放置入事件佇列之中,主程式在終止前保持100分鐘的模擬時間。
參見
[編輯]註釋
[編輯]- ^ https://portablesimula.github.io/github.io/.
- ^ 2.0 2.1 Portable Simula Revisited. [2022-03-15]. (原始內容存檔於2022-05-11).
- ^ 3.0 3.1 GNU Cim. [2022-04-02]. (原始內容存檔於2022-04-14).
- ^ Kristen Nygaard; Ole-Johan Dahl. The Development of the Simula Languages (PDF). 1978 [2022-03-14]. (原始內容 (PDF)存檔於2022-01-20).
SIMSCRIPT was the only simulation language that we were closely acquainted with during the design phase of SIMULA. From the preceding sections it will be evident that it had a considerable impact through its list processing and time scheduling mechanisms. It also contained a set of random drawing and other utility routines, which served as a model for our procedure library.
- ^ 5.0 5.1 5.2 Alan Kay. The Early History of Smalltalk. [2022-04-11]. (原始內容存檔於2011-04-29).
I wound up in graduate school at the University of Utah in the Fall of 1966, ……. …… The documentation was incomprehensible. Supposedly, this was the Case-Western Reserve 1107 Algol – but it had been doctored to make a language called Simula; the documentation read like Norwegian transliterated into English, which in fact it was. There were uses of words like activity and process that didn’t seem to coincide with normal English usage. ……
The weirdest part was the storage allocator, which did not obey a stack discipline as was usual for Algol. …… What Simula was allocating were structures very much like the instances of Sketchpad. There wee descriptions that acted like masters and they could create instances, each of which was an independent entity. What Sketchpad called masters and instances, Simula called activities and processes. Moreover, Simula was a procedural language for controlling Sketchpad-like objects, thus having considerably more flexibility than constraints (though at some cost in elegance) ……. ……
For the first time I thought of the whole as the entire computer and wondered why anyone would want to divide it up into weaker things called data structures and procedures. Why not divide it up into little computers, as time sharing was starting to? But not in dozens. Why not thousands of them, each simulating a useful structure? ……
It is not too much of an exaggeration to say that most of my ideas from then on took their roots from Simula – but not as an attempt to improve it. It was the promise of an entirely new way to structure computations that took my fancy. As it turned out, it would take quite a few years to understand how to use the insights and to devise efficient mechanisms to execute them. - ^ 6.0 6.1 Barbara Liskov. A history of CLU (PDF). 1992 [2022-04-27]. (原始內容 (PDF)存檔於2021-11-05).
Programming languages that existed when the concept of data abstraction arose did not support abstract data types, but some languages contained constructs that were precursors of this notion. …… The mechanism that matched the best was the class mechanism of Simula 67. A Simula class groups a set of procedures with some variables. A class can be instantiated to provide an object containing its own copies of the variables; the class contains code that initializes these variables at instantiation time. However, Simula classes did not enforce encapsulation ……, and Simula was lacking several other features needed to support data abstraction, …….
- ^ 7.0 7.1 7.2 SIMULA Standards Group. SIMULA Standard (PDF). 1986 [2022-03-23]. (原始內容 (PDF)存檔於2022-04-07).
In this Standard the name SIMULA is considered synonymous with SIMULA 67. …… It is recommended that the language defined in this Standard be referred to as "Standard SIMULA".
SIMULA includes most of the ALGOL 60 language. Wherever ALGOL is used in this Standard it relates to the STANDARD ALGOL 60 definition (ISO 1538). - ^ 8.0 8.1 Ole-Johan Dahl. The Birth of Object Orientation: the Simula Languages (PDF). 2001 [2022-04-13]. (原始內容 (PDF)存檔於2021-08-10).
On the other hand, if a procedure
P
is specified as virtual in a classC
the binding scheme is semi-dynamic. Any call forP
occurring inC
or in any subclass ofC
will bind to that declaration ofP
which occurs at the innermost prefix level of the actual object containing such a declaration (and similarly for remote accesses). Thus, the body of the procedureP
may, at the prefix level ofC
, be postponed to occur in any subclass ofC
. It may even be replaced by more appropriate ones in further subclasses.
This binding scheme is dynamic in the sense that it depends on the class membership of the actual object. But there is nevertheless a degree of compiler control; the access can be implemented as indirect through a table produced by the compiler forC
and for each of its subclasses. ……
a virtual procedure can be seen as a parameter, where the actual parameter is a procedure residing safely within the object itself, at an appropriate prefix level. There is the additional advantage that the procedure has direct access to attributes of the object containing it. - ^ 9.0 9.1 O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (編). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503.
In SIMULA 67, a block instance is permitted to outlive its calling statement, and to remain in existence for as long as the program needs to refer to it. It may even outlive the block instance that called it into existence. As a consequence, it is no longer possible to administer storage allocation as a simple stack; a general garbage-collector, including a scan-mark operation, is required to detect and reclaim those areas of store (local workspace of block instances) which can no longer be referenced by the running program. The reason for accepting this extra complexity is that it permits a wider range of concepts to be conveniently expressed. In particular, it clarifies the relationship between data and the operations which may be performed upon it, in a way which is awkward or impossible in ALGOL 60.
- ^ 10.0 10.1 Ole-Johan Dahl. The Birth of Object Orientation: the Simula Languages (PDF). 2001 [2022-04-13]. (原始內容 (PDF)存檔於2021-08-10).
The main impact of Simula 67 has turned out to be the very wide acceptance of many of its basic concepts: objects, but usually without own actions, classes, inheritance, and virtuals, often the default or only way of binding 「methods」, (as well as pointers and dynamic object generation).
There is universal use of the term 「object orientation」, OO. Although no standard definition exists, some or all of the above ideas enter into the OO paradigm of system development. There is a large flora of OO languages around for programming and system specification. …… The importance of the OO paradigm today is such that one must assume something similar would have come about also without the Simula effort. The fact remains, however, that the OO principle was introduced in the mid 60’s through these languages.
Simula 67 had an immediate success as a simulation language, and was, for instance extensively used in the design of VLSI chips, e.g. at INTEL. As a general programming language, its impact was enhanced by lectures at NATO Summer Schools given by OJD, materialized as a chapter in a book on structured programming. The latter has influenced research on the use of abstract data types, e.g., the CLU language, as well as research on monitors and operating system design.
A major new impact area opened with the introduction of workstations and personal computers. Alan Kay and his team at Xerox PARC developed Smalltalk, an interactive language building upon Simula’s objects, classes and inheritance. It is oriented towards organising the cooperation between a user and her/his personal computer. - ^ Kristen Nygaard. SIMULA: An Extension of ALGOL to the Description of Discrete-Event Networks. Proceedings of the IFIP congress 62, Munich. North-Holland Publ., pages 520-522. Aug 1962.
- ^ C. A. R. Hoare. Record Handling (PDF). ALGOL Bulletin no. 21. 1965 [2022-03-14]. (原始內容 (PDF)存檔於2022-04-07).
- ^
Jan Rune Holmevik. Compiling Simula. Oslo, Norway: Institute for Studies in Research and Higher Education. 1994. (原始內容存檔於2020-01-11).
During the summer and autumn of 1963, …… Instead Dahl and Nygaard introduced the far more powerful process concept which came to constitute the basic, unifying feature of the SIMULA I language. In short, a process can be understood as a generalized ALGOL procedure with quasi-parallel properties. ……
they became more and more preoccupied with the opportunities embedded in Tony Hoare's record class construct, first presented in ALGOL bulletin no. 21, 1965. …… What they were really looking for was some kind of generalized process concept with record class properties. The answer to their problem suddenly appeared in December 1966, when the idea of prefixing was introduced. A process, later called an object, could now be regarded as consisting of two layers: A prefix layer containing references to its predecessor and successor along with a number of other properties, and a main layer containing the attributes of the object in question. In addition to this important new feature, they also introduced the class concept, which can roughly be described as a highly refined version of SIMULA I's activity concept. This powerful new concept made it possible to establish class and subclass hierarchies of concatenated objects. - ^ Ole-Johan Dahl; Kristen Nygaard. Class and Subclass Declarations (PDF). North Holland: J. Buxton,ed.: Simulation Programming Languages. Proceedings from the IFIP Working Conference in Oslo, May 1967. 1968 [2020-05-16]. (原始內容 (PDF)存檔於2022-04-08).
- ^ Ole-Johan Dahl; Bjørn Myhrhaug; Kristen Nygaard. SIMULA 67 Common Base Language (PDF). Norwegian Computing Center. 1968, 1970 [2022-02-13]. (原始內容 (PDF)存檔於2022-04-07).
- ^ Swedish standard SS 63 61 14 (PDF). [2022-04-14]. (原始內容 (PDF)存檔於2022-04-16).
- ^ Bjarne Stroustrup. A history of C++: 1979-1991 (PDF). History of programming languages---II (ACM). 1996: 699–769 [2022-03-22]. doi:10.1145/234286.1057836. (原始內容 (PDF)存檔於2022-04-23).
C++ was designed to provide Simula’s facilities for program organization together with C’s efficiency and flexibility for systems programming.
James Gosling. The Feel of Java (PDF). 1997 [2022-04-27]. (原始內容 (PDF)存檔於2022-02-28).Java is a blue collar language. It’s not PhD thesis material but a language for a job. Java feels very familiar to many different programmers because I had a very strong tendency to prefer things that had been used a lot over things that just sounded like a good idea. …… It has an object-oriented flavor that derives from a number of languages—Simula, C/C++, Objective C, Cedar/Mesa, Modula, and Smalltalk.
- ^ O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (編). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503.
A procedure which is capable of giving rise to block instances which survive its call will be known as a class; and the instances will be known as objects of that class. A class may be declared, with or without parameters, in exactly the same way as a procedure ……
- ^ O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (編). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503.
useful properties from the standpoint of concept modelling. ……
⑷ Language element. A block is itself a statement, which is a syntactic category of the language. Furthermore, through the procedure mechanism, reference to a block may be dissociated from its defining text. - ^ O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (編). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503.
One of the most powerful mechanisms for program structuring in ALGOL 60 is the block and procedure concept. It has the following useful properties from the standpoint of concept modelling.
⑴ Duality. A block head and block tail together define an entity which has properties and performs actions. Furthermore the properties may include a data structure as well as associated operators (local procedures). - ^ O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (編). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503.
In ALGOL 60, the rules of the language have been carefully designed to ensure that the lifetimes of block instances are nested, in the sense that those instances that are latest activated are the first to go out of existence. It is this feature that permits an ALGOL 60 implementation to take advantage of a stack as a method of dynamic storage allocation and relinquishment. But it has the disadvantage that a program which creates a new block instance can never interact with it as an object which exists and has attributes, since it has disappeared by the time the calling program regains control. Thus the calling program can observe only the results of the actions of the procedures it calls. Consequently, the operational aspects of a block are overemphasised; and algorithms (for example, matrix multiplication) are the only concepts that can be modelled.
- ^ 22.0 22.1 O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (編). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503.
useful properties from the standpoint of concept modelling. ……
⑶ Class of instances. In ALGOL 60 a sharp distinction is made between a block, which is a piece of program text, and a dynamic block instance, which is (a component of) a computing process. An immediate and useful consequence is that a block may be identified with the class of its potential activations. (Strictly speaking a "block" in this context means either the outermost block or a block immediately enclosed by a dynamic block instance.) Through the recursion mechanism of ALGOL 60 different instances of the same block may co-exist in a computing process at the same time. - ^ O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (編). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503.
useful properties from the standpoint of concept modelling. ……
⑵ Decomposition. A block where only local quantities are referenced is a completely selfcontained program component, which will function as specified in any context. Through a procedure heading a block (procedure) instance may interact with a calling sequence. Procedures which reference or change non-local variables represent a partial decomposition of the total task, which is useful for direct interaction with the program environment. - ^ D. A. Turner. Some History of Functional Programming Languages (PDF). in an invited lecture TFP12, St Andrews University. 12 June 2012 [2022-05-04]. (原始內容 (PDF)存檔於2020-04-15).
Algol 60 allowed textually nested procedures and passing procedures as parameters (but not returning procedures as results). The requirement in the copying rule for systematic change of identifiers has the effect of enforcing static (that is lexicographic) binding of free variables.
In their book 「Algol 60 Implementation」, Randell and Russell (1964, Sect. 2.2) handle this by two sets of links between stack frames. The dynamic chain links each stack frame, representing a procedure call, to the frame that called it. The static chain links each stack frame to that of the textually containing procedure, which might be much further away. Free variables are accessed via the static chain.
This mechanism works well for Algol 60 but in a language in which functions can be returned as results, a free variable might be held onto after the function call in which it was created has returned, and will no longer be present on the stack.
Landin (1964) solved this in his SECD machine. A function is represented by a closure, consisting of code for the function plus the environment for its free variables. The environment is a linked list of name-value pairs. Closures live in the heap. - ^ 25.0 25.1 Ole-Johan Dahl; Bjørn Myhrhaug. The Simula Implementation Guide (PDF). 1967, 1973 [2022-04-17]. (原始內容 (PDF)存檔於2022-04-26).
A procedure deviates from a block in that ⑴ it has a name and ⑵ may be referred to at several different places in the program, and ⑶ that parameters may be given to it when invoked. A procedure shares the property of a block that it is impossible to establish a reference to it or to its interior.
- ^ D. A. Turner. Some History of Functional Programming Languages (PDF). in an invited lecture TFP12, St Andrews University. 12 June 2012 [2022-05-04]. (原始內容 (PDF)存檔於2020-04-15).
Algol 60 is not normally thought of as a functional language but its rules for procedures (the Algol equivalent of functions) and variable binding were closely related to those of λ-calculus.
The Revised Report on Algol 60 (Naur 1963) is a model of precise technical writing. It defines the effect of a procedure call by a copying rule with a requirement for systematic change of identifiers where needed to avoid variable capture — exactly like β-reduction.
Although formal parameters could be declared value the default parameter passing mode was call by name, which required the actual parameter to be copied unevaluated into the procedure body at every occurrence of the formal parameter. This amounts to normal order reduction (but not graph reduction, there is no sharing). The use of call by name allowed an ingenious programming technique: Jensen’s Device. - ^ 27.0 27.1 Kristen Nygaard; Ole-Johan Dahl. The Development of the Simula Languages (PDF). 1978 [2022-03-14]. (原始內容 (PDF)存檔於2022-01-20).
the ALGOL-like call by name parameters were out of the question for reasons of security and storage allocation strategy: the actual parameter could be lost during the lifetime of an object. The problem then was to find a name-parameter-like mechanism that would guarantee a safe place for the actual parameter. After much trial and error we hit on the virtual quantity concept where the actual would have to be declared in the object itself, but at a deeper subclass level than that of the virtual specification. Now generalized objects could be defined whose behaviour pattern could be left partly unspecified in a prefix class body. Different subclasses could contain different actual procedure declarations.
- ^ Ole-Johan Dahl. The Birth of Object Orientation: the Simula Languages (PDF). 2001 [2022-04-13]. (原始內容 (PDF)存檔於2021-08-10).
In general attribute identifiers may be redeclared in subclasses, as is the case of inner blocks. The identity of an attribute is determined by the prefix level of the accessing occurrence, or, if the access is remote, by the class qualifying the object reference in question. In this way any ambiguity of identifier binding is resolved textually, i.e at compile time; we call it static binding.
- ^ Kristen Nygaard; Ole-Johan Dahl. The Development of the Simula Languages (PDF). 1978 [2022-03-14]. (原始內容 (PDF)存檔於2022-01-20).
In ALGOL, blocks (including procedures) are seen externally as generalized operations. By introducing mechanisms for quasi-parallel sequencing, essentially the same construct could play the role of processes in parallel, and through mechanisms for naming block instances and accessing their contents they could function as generalized data objects. The essential benefits of combining data and operations in a single construct were already there to be explored.
- ^ Kristen Nygaard; Ole-Johan Dahl. The Development of the Simula Languages (PDF). 1978 [2022-03-14]. (原始內容 (PDF)存檔於2022-01-20).
An object would start its life like an instance of a function procedure, invoked by the evaluation of a generating expression. During this phase the object might initialize its own local variables. Then, on passage through the end of the object or as the result of a new basic operation "detach", control would return to the generating expression delivering a reference to the object as the function value. In the former case the object was "terminated" with no further own actions, in the latter case it had become a "detached object" capable of functioning as a "coroutine".
The basic coroutine call "resume (<object reference>)" would make control leave the active object, leaving behind a reactivation point at the end of the resume statement, and enter the referenced object at its reactivation point. - ^ Ole-Johan Dahl; Bjørn Myhrhaug. The Simula Implementation Guide (PDF). 1967, 1973 [2022-04-16]. (原始內容 (PDF)存檔於2022-04-16).
The procedure "call" is not a part of the Common Base, but is a natural part of a SIMULA 67 Common Base implementation. ……This definition of call is tentative, since the problem is currently being studied by a Technical Committee under the SIMULA Standards Group.
- ^ O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (編). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503.
In SIMULA, a coroutine is represented by an object of some class, co-operating by means of resume instructions with objects of the same or another class, which are named by means of reference variables. ……
Thus a main program may establish a coroutine relationship with an object that it has generated, using the call/detach mechanism instead of the more symmetric resume/resume mechanism. In this case, the generated object remains subordinate to the main program, and for this reason is sometimes known as a Semicoroutine. ……
LetX
andY
be objects, generated by a "master program"M
. Assume thatM
issues acall (X)
, thereby invoking an "active phase" ofX
, terminated by a detach operation inX
; and then issues acall (Y)
, and so forth. In this wayM
may act as a "supervisor" sequencing a pattern of active phases ofX
,Y
, and other objects. Each object is a "slave", which responds with an active phase each time it is called for, whereas M has the responsibility to define the large scale pattern of the entire computation.
Alternatively the decision making may be "decentralised", allowing an object itself to determine its dynamic successor by a resume operation.
The operationresume (Y)
, executed byX
, combines an exit out ofX
(bydetach
) and a subsequentcall (Y)
, thereby bypassingM
. Obligation to return toM
is transferred toY
. - ^ Jaroslav Sklenar. INTRODUCTION TO OOP IN SIMULA. 1997 [2022-02-13]. (原始內容存檔於2022-05-11).
The system class Simulation introduces the notion of time. It means that if nested, there will be other local(nested) times.
延伸閱讀
[編輯]- 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], ISBN 0632016116, (原始內容 (PDF)存檔於2022-04-07)