Simula

本页使用了标题或全文手工转换,现处于中国大陆简体模式
求闻百科,共笔求闻
Simula
编程范型多范型: 指令式, 过程式, 结构化, 面向对象, 并发
设计者奥利-约翰·达尔
实现者克利斯登·奈加特
发行时间1962年,​62年前​(1962(Simula I)
1967年,​57年前​(1967(Simula 67)
稳定版本
Standard SIMULA[1]
(1986年8月25日,​37年前​(1986-08-25
类型系统静态名称式
实现语言主要为ALGOL 60(有一些Simscript构件)
操作系统类Unix系统Windowsz/OSTOPS-10MVS
主要实现产品
Portable Simula Revisited[2], GNU Cim[3]
受启发于
ALGOL 60, Simscript[4]
施影响于
SmalltalkCLU[5]C++BETAObject PascalModula-3Java

Simula,一种编译式编程语言,由奥利-约翰·达尔克利斯登·奈加特,在1960年代于奥斯陆挪威计算中心,开发出来了Simula I与Simula 67两代。它承继了ALGOL 60作为基础,被认为是第一个面向对象编程的编程语言。

Simula 67介入了对象子类(后来惯称为子类继承超类)、虚过程[6],还有协程离散事件模拟和特征性的垃圾收集[7]。Simula的影响经常被低估[8],在C++Object PascalModula-3Java和后来的很多编程语言中,都实现了受Simula启发的对象。BETA是Simula的现代后继者。

历史

最初Simula设计的离散事件网络示意图

克利斯登·奈加特在1957年开始在自己的电脑上写模拟器。为了发展他的模拟器,他需要更强大的编程语言。1962年1月,奥利-约翰·达尔开始跟他合作。他们受到ALGOL 60的启发,在同年5月,发展出第一个模拟器编程语言,取名为Simula I。此时,克利斯登·奈加特受到Sperry Rand公司邀请,去协助他们开发UNIVAC 1107电脑。UNIVAC软件部门的主管鲍伯·贝莫,力邀克利斯登·奈加特前往国际信息处理协会(IFIP)举行的第二次国际会议上,发表了论文“SIMULA-扩展ALGOL到离散事件网络的描述”[9]

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)构造的概念[10],1966年,克利斯登·奈加特奥利-约翰·达尔通过将Simula I的进程当作由前缀层和主要层二者构成,把它扩展成了具有了记录类别属性的通用进程,他们当时所称“进程”随即被称为“对象[11]。1967年5月,奈加特和达尔在奥斯陆举办的IFIP工作小组论坛中,发表了关于类别子类声明的论文,形成Simula 67的第一份定义文件[12]

1968年召开的会议,组成了SIMULA标准小组,并发表了第一份官方Simula标准文件“SIMULA 67通用基础语言”[13]。在1960年代后期和1970年代早期,Simula 67主要实现于四个系统之上:挪威计算中心UNIVAC 1100系列,挪威计算中心的IBM System/360System/370奥斯陆大学Kjeller联合安装的CDC 3000系列,和瑞典国防研究所(FOA)的DEC TOPS-10

当前的Simula 67业界标准,是在1986年修订的“标准SIMULA”[1],它在1987年被接受为瑞典国家标准[14]。它有四个主要实现:Simula ASLund Simula、GNU Cim[3]和Portable Simula Revisited[2]

Simula影响了Smalltalk[15],和后来的面向对象编程语言[8]。Simula经由Smalltalk启发了并发计算的演员模型[16]C++语言和Java语言的创始人,都认可自己受到了Simula的重要影响[17]

特征概念

Simula 67包含通用算法语言ALGOL 60的多数特征作为自己的子集[1]。它是大小写不敏感的。

块与过程

ALGOL 60中最强力的编程构造机制之一,就是过程的概念。

语法

块是一种语句[18],在Simula 67中,它包括子块和有前缀(prefixed)块。子块就是未加前缀的常规意义上的块,下面分别用字母D表示任意声明,S表示任意语句,L表示可选的任意标签,子块的语法单元采用的形式为:

L: L: ... begin D; D; ... D; S; S; ... S; S end

声明担当定义在程序中用到的量的特定属性,并给它们关联上标识符,这里的(quantity)包括:简单变量、数组、switch[19]、过程、类和外来声明。块中的每个语句,都可以是完全的复合语句或块。复合语句与块相比没有声明。所有的块,自动地介入一层新的命名法(nomenclature)[20]

  • 在这个块内出现的标识符,可以通过合适的声明,而被指定为局部于所论及的这个块。在这个块内侧的这个标识符所表示的实体,不存在于它的外侧。在这个块外侧的这个标识符所表示的任何实体,在这个块内侧是不可见的;在Simula 67中,可通过连接或远程访问使它成为可见的。
  • 除了表示标签的标识符之外,一个标识符,如果出现在一个块中,而且并非声明于这个块中,则它非局部于这个块,就是说它所表示的这个块内侧实体,与在紧接它外侧的层级中出现的同名实体是同一个实体。因为块中的语句自身可以是一个块,局部和非局部于一个块的概念,必须递归地去理解,就是说非局部于一个块A的一个标识符,可是亦可否地,非局部于A是其中语句的块B

语义

是一种形式描述或模式,关乎聚集的数据结构和关联的算法以及行动[21]。一个块实例,可以被认为是它的形式描述的文字复本。一个块的任何内部块,仍然是一个模式,但是在其中出现的非局部标识符,确认了局部于字面上包围的块实例的项目[22]

  • 当一个块执行的时候,生成这个块的一个动态实例[23]。在计算机中,一个块实例可以采用一种形式的内存区域,它包含需要的动态块信息,并包括空间来持有局部于这个块的变量的内容[24]
  • 块实例中的局部变量,标识了分配给块实例的内存片段。非局部于内部块的标识符绑定,对这个内部块的任何随后的动态实例,保持有效[25]

任何声明的变量,在进入这个变量所局部于的那个块之中的时候,都会被初始化。局部于一个块的一个变量,是一个内存设备,其内容依据这个变量的类型,要么是一个,要么是一个引用。值类型可特征化为直接关联着一个可能值的集合(这个类型的“值范围”)。引用概念,对应于一个名字或一个“指针”的直观想法。它提供了引用值的机制,还反映了机器寻址可能性。在特定简单情况下,一个引用可以被实现为一个存储的值的内存地址。对于值类型不关联着引用概念。

过程与块相比,它有一个名字,可以在程序的多个不同地方提及,并且在调用时可以给出参数[26];过程的参数传送模态,除了有传值调用传名调用[27],在Simula 67中,又增加了传引用调用。过程和块都不可能创建到它或它内部的引用[26];对于一个给定块,有可能生成它的一些可以共存和交互的实例[24],例如递归过程的实例[28]

  • 定义函数指示符的值的过程,以类型声明符作为其过程声明的最先符号[29]。此外的真正(proper)过程,在Simula 67中,被称为具有普遍(universal)类型,任何类型都从属(subordinate)于普遍类型。在Simula 67中,过程的参数列表( … <参数分界符> … ),舍弃了其中对ALGOL 60是可选的“) <字母串>: (”样式的参数分界符[30]
  • 过程的缺省的传送模态,在Simula 67中,对于值类型的参数是传值调用,对于所有其他类型的参数是传引用调用;故而在过程声明的参数规定中,增加了以name为前导的名字部分,用来指定所述及的参数采用传名调用。在过程主体内传名调用的形式参数的每次出现,都引起对实际参数的一次求值。在Simula 67中,这个求值发生在过程语句的上下文中,就是说不会出现标识符冲突,因为过程主体和它的变量此时是不可见的。
  • 过程调用的执行,在有参数的情况下要经历如下步骤:创建形式参数块实例;求值对应于传值调用或传引用调用的实际参数,并将其结果赋值给形式参数块实例的对应变量[31];过程主体被初始化并开始执行。

块实例的想法,在Simula 67中还进一步产生出,一个块作为“对象”的“”的概念,这些对象每个都是这个块的动态实例,因此符合相同的模式。介入扩展的块概念,要通过类声明和关联的交互机制,比对象引用、远程访问、准并行运算和块串接。

对象与类

Simula 67的中心概念是对象,一个对象是一段自备式(self-contained)程序(块实例),它拥有由一个声明定义的自己的局部数据和行动(action)。操纵对象和相互关联对象的需要,致使语言必须介入列表处理设施。

类是一种过程[32],它有能力引起在它被调用后仍存活的一个块实例,而这些实例就叫做这个类的对象。类声明定义一个程序(数据和行动)模式,而符合(conforming)这个模式的对象被称为“属于相同的类”。

  • 对于一个给定对象,形式参数,在由virtual:前导的虚拟部分中规定的,和声明为局部于类主体(body)的量,叫做这个对象的特性(attribute)。一个特性的声明或规定叫做特性定义。在1986年修订的语言标准中,通过由hidden亦或protected前导的保护规定,可以限制类特性标识符的可见性。
  • 类声明的形式参数,不适用传名调用[33]。在规定部分中需要对每个形式参数进行规定,这些参数被当作局部于类主体的变量,可以接受如下规定符(specifier):<类型>array<类型> array
  • 类主体通常是一个,即使它如语法形式所允许的那样是块以外的一个语句,也表现得如同一个块。一个分裂(split)主体,担当其中符号inner表示一个虚设(dummy)语句的块。

不同于后来的将对象作为记录结构的扩展的面向对象编程语言,Simula 67的类主体中除了有定义特性的声明,还可以有定义行动的语句。如果有行动定义在一个类声明中,则符合这个模式的行动,可以由属于这个类的所有对象执行。如果在类声明中没有指定行动,则定义了一类纯数据结构。例如:

class Order (number); integer number;
    begin integer numberOfUnits, arrivalDate;
          real processingTime;
    end;

属于特定类的对象,通过对象表达式,用对象生成语句new来生成。例如,想要多少就能生成多少属于这个Order类的一个新对象:

new Order (103);

属于一个对象的行动,可以都在就一个过程而言的一个序列中执行。这些行动,还可以作为一系列的独立子序列或“活动阶段”(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的一个类,这里Ckk = 1,2,...,n)的下标k叫做前缀层级,则属于Cn的对象是一个复合对象,它可以用串接的类声明来正式的描述,串接的过程被认为先于程序执行而发生。 设X是属于Cn的的一个对象。非正式的说,串接机制有如下结果:

  • X拥有的特性集合,是在C1, C2, ... , Cn中所定义集合的并集。在Ck1 <= 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的运算规则中的那些语句,依据升序前缀层级来排序。

下面是一个简单例子:

Order class BatchOrder;
    begin integer batchSize;
          real setupTime;
    end;

Order class SingleOrder;
    begin real setupTime, finishingTime, weight; end;

SingleOrder class Plate;
    begin real length, width; end;

属于这些子类BatchOrderSingleOrderPlate的新对象,都有为Order定义的数据,再加上在各种类声明中定义的补充数据。例如,属于类Plate的对象,构成自如下信息片段:Order定义的numbernumberOfUnitsarrivalDateprocessingTimeSingleOrder定义的setupTimefinishingTimePlate定义的weightlengthwidth

有前缀(prefixed)块的一个实例,是由块前缀生成的对象,与这个主体块的实例,串接而成一个复合对象,其串接定义类似于类的串接规则。块前缀的类的形式参数,按块前缀的实际参数所示初始化。对有前缀块有两个限制:在其中通过使用this来引用到类自身的类,是非法的块前缀。一个块前缀的类标识符所提及的类,必须局部于最小的包围这个有前缀块的块。

引用

当属于各种类的很多对象,作为同一个程序的各部分而共存的时候,需要能够对个体对象指定名字,为此介入了叫做“引用”的新的基本类型;还要能相互关联对象,比如通过二叉树和各种其他类型的列表结构,为此将叫做“集合”的循环双向链表,作为一个系统类Simset介入为语言的一部分。

在Simula 67中有两种引用类型,对象引用类型和文本引用。对于一个类对象(类实例),有一个关联的唯一的“对象引用”确认这个对象,并且对于任何类C,都有一个关联的对象引用类型ref (C)。这种类型的,被称为由类C限定;它的值,要么是一个对象,要么是表示“没有对象”特殊值none

限定(qualification)将值的范围,限制至包括在限定类中的这些类的对象。不管何种限定,值的范围都包括值none。一个对象引用的限定,是一个类标识符,它因此服从声明的作用域和可见性规则。限定关联于所提及的类声明局部于的那个块的一个实例。这蕴涵着特定的关于限定有效性的检查,不能单独在程序正文的基础上进行,因此这种测试必须在程序执行期间完成。

引用是有限定的,蕴涵着一个给定引用所提及的对象,只能属于这个限定中提到的类,或属于这个限定类的子类。如果一个对象引用类型的限定,是另一个对象引用类型的限定类的子类,则前者被称为从属于后者。例如:

ref(Order) next, previous;

对象表达式是获得对一个对象的引用的一种规则。对象表达式的值,是被引用的对象或none。制作一个引用来提及一个特定对象的运算符,写为:-并读作“指称”(denote),它指示将一个引用,赋值给在引用赋值左侧的、引用类型变量或引用类型过程标识符。例如:

next :- new Oreder(101);
previous :- next;
next :- new Plate(50);

而运算符:=读作“成为”(become),指示将一个值,赋值给在值赋值左侧的、值类型变量或值类型过程标识符,或者将一个文本值,赋值给在左侧者所引用的文本(frame)。

对象表达式

对象表达式,具有类型ref(限定)。对象表达式的限定规则包括:对象生成式、局部对象或限定对象,分别由跟随符号newthisqua的标识符的类来限定。

对象生成式(generator),涉及到属于所确认的类的对象的生成和执行。这个对象是相应的(串接成的)类的一个新实例。对象生成式的求值构成自如下行动:

  1. 生成这个对象,并且这个对象生成式如果有实际参数,则求值它们,将得到的这些值及或引用传送给形式参数。
  2. 控制经过这个对象最初的begin进入其中,借此它变成在“系附”状态下运行。在生成的对象执行了detach基本过程,或者经过这个对象最终的end退出的两种情况之一时,对象生成式的求值完成。

求值之后的对象的状态,要么是“脱离”要么是“终止”,详见后面的块实例章节。

局部对象this C|"java",如果用在类CC的任何子类的类主体中,或用在其块限定为类CC的一个子类的连接块中,则这个对象表达式是有效的。在一个给定的上下文中,一个局部对象的值,是一个对象或连接到一个对象,它是这个对象表达式在其中有效的、最小的字面上包围的块实例;如果没有这样的块,则这个对象表达式在这个上下文中是非法的。对于一个过程或类主体的实例(上下文),“字面上包围”意为包含它的声明。如此定义的内涵参见示例章节中的二叉树实例。

X表示一个简单的引用表达式,而CD是类标识符,使得类D是对象X的限定。对于限定对象X qua C,如果类C外部于或等于类D,或者是D的一个子类,则这个对象表达式是合法的,否则是为非法。如果X的值是none,或者是属于外部于C的类的一个对象,则这个对象表达式求值形成一个运行时间错误;在其他情况下,X qua C的值,就是X的值。这种对一个串接的类对象的即时限定,约束或扩展它的特性通过检视或远程访问的可见性。

对象关系表达式,使用运算符isin,来测试一个对象的类成员关系。关系X is C,在X引用属于类C的对象之时,值为true,否则值为false。关系X in C,在X是引用属于C的对象,或者X是内部于C的类之时,值为true,否则值为false

不同于算术关系表达式使用比较运算符=<>,对象引用关系表达式,使用比较运算符===/=,来比较引用,从而区别于对应的被引用的值。两个对象引用XY,在它们都引用相同的对象,或者它们都是none之时,被称为是“同一”的。关系X==Y,在这种情况下拥有的值为true,否则值为false。关系X=/=Y的值,是X==Y的值的否定

远程访问

一个对象的一个特定特性,由下列三项信息来完全确认(identify):

  1. 这个对象
  2. 外部于或等于这个对象的类的一个
  3. 在这个类中或在属于它的前缀序列的任何类中定义的一个特性标识符

对于任何特性确认,第2项类信息都是在字面上定义的,从而形成静态绑定[34]。属于其他对象的特性,可以要么通过“远程标识符”(“点表示法”),要么通过“连接”(connection)机制,从其外侧“远程访问”来引用和使用。远程标识符的形式为:简单对象表示式.特性标识符,它可用作简单变量、数组变量、函数指示符(designator)[35]和过程语句[36]中的标识符,这种点表示法给出对信息的单独片段的访问,例如:

if next.number >= previous.number then ......;

它将名为next的类Order的对象的特性number,比较于名为previous的类Order的对象的特性number

“组访问”可通过“连接语句”来完成,连接机制的用途,是为在连接块中的特定识别,提供上述第1项对象信息和第2项类信息的隐式定义。例如:

inspect next when Plate do begin ...... end;
inspect new Plate(50) do begin ...... end;

在检视(inspection)块的beginend之间的语句中,可以直接提及next所引用的在Plate中包含的所有信息片段。do后面的语句,如果是块以外的一个语句,它表现得也如同一个块。连接语句进而表现得如同被叫做“连接块”的第二个虚构(fictitious)的块所包围。

设对象表达式求值为X,在连接块执行期间,称对象X为“被连接上”了。连接块有一个关联的“块限定”,它是连接块的前导类标识符,而对于没有when子句的情况,它是连接块的前导对象表达式的限定。

虚过程

虚拟(virtual),有双重用途:

  • 允许在一个对象的一个前缀层级上,访问在内部前缀层级上声明的特性。
  • 允许在一个前缀层级上的特性重新定义,在外部前缀层级上有效。

在类声明的虚拟部分中,可以接受如下规定符:labelswitch[19]procedure<类型> procedure。不同于一般的特性确认,虚过程形成半动态绑定[6],在某种意义上类似于ALGOL 60传名调用机制[33]

一个对象的一个虚拟量,要么是“无匹配的”的,要么被确认为具有一个“匹配”特性,它是在这个虚拟量的前缀层级上或在内部前缀层级上声明的,其标识符重合(coincide)于虚拟量的标识符的一个特性。匹配特性必须与虚拟特性有相同的种类。在一个给定前缀层级上的匹配量的类型,必须重合或从属于这个虚拟规定的类型,和在任何外部前缀层级上声明的任何匹配量的类型。

在1986年修订的语言标准中,虚过程量可选的可使用procedure <过程标识符> <过程规定>方式来指定,即凭借它的类型,并且如果它有形式参数,则还凭借它们的类型、种类和传送模态。含有过程规定is <过程声明>的虚过程量,只能由有相同类型的过程来匹配,并它与这个过程规定具有相同的过程头部。

例如,下面实现散列表Hashing类,声明了虚过程hash并随即实现了它,又定义了要用到散列过程hash的查找过程lookup:

class Hashing (n); integer n;
    virtual: integer procedure hash;
begin 
    integer procedure hash(t); text t;
    begin ...... end hash;
    text array table (0:n-1); integer entries;
    integer procedure lookup (t,old);
        name old; Boolean old; text t;
    begin ...... end lookup;
end Hashing;

Hashing class ALGOL_hash;
begin
    integer procedure hash(T); text T;
    begin ...... end hash;
end ALGOL_hash;

Hashing(64) begin
    integer procedure hash(T); text T;
    begin ...... end hash;
    ......
end

子类ALGOL_hash和有前缀块,用自己的hash过程实现替代了其前缀中的实现。在子类的类主体和有前缀块的主要块中,能获得到过程lookup,而它用到的过程hash是这里提供的替代实现。

作用域和可见性

一个标识符定义及其关联的标识符,在其作用域可见性之间需要做出区别。

  • 一个标识符定义的作用域,是它在其中可能有作用的那一部分程序正文。相同的标识符,可以定义在程序的很多地方,因此可以关联于不同的量。这种相同的标识符的作用域,因而可能重叠,例如当一个标识符在内部块中被重新声明的情况下。
  • 一个标识符定义,这个标识符在程序的一个给定点上,如果能够涉及到所论及声明的量,则这个定义被称为在这个点上是可见的。在给定标识符于此可见的程序正文的一个特定点上,最多只能有一个定义关联于这个标识符,例如在上述重新声明的情况下,在它们作用域的并集内任何给定点上,只有一个定义是可见的。

一个标识符定义的局部块,是在字面上最近的包围块,即子块、前缀块、过程主体或类主体,还包括围绕for语句的受控语句、过程声明或类声明的虚构的块、连接块等等。这个标识符和它的定义,被称为局部于这个块。 标识符定义,只在它们的作用域内是可见的。一个特定定义的可见性,在它的作用域内可以受到下列限制:

  • 具有相同标识符的一个标识符定义,即这个标识符的重新定义,出现在以前的定义的局部块所包围的某个构造内。在它们共同的作用域内,只有最内部的重新定义是可见的。
  • 一个重新定义,出现在类的某个内部前缀层级。
  • 远程访问,可以导致某些标识符定义在检视块或点表示法内变成不可见的。
  • 使用thisqua,可以导致一个或多个重新定义被临时停止。
  • 这个定义所局部于的类声明的保护部分。

一个标识符的重新定义,不允许出现在它的局部块的头部,这禁止了在同一个块中出现相同标识符的两个定义。

具有形式参数的过程,在特定意义上表现得如同有一个虚构的块包围着过程主体。形式参数因而对应于声明为局部于这个虚构的块的变量。因此,一个过程的形式参数,可以在属于这个过程声明的过程主体的头部内被重新定义。这种重新定义,将这个形式参数的可见性,有效的限制至与它有关的value部分、name部分和规定部分。因此这种参数的唯一作用,是来自其求值可能有的副作用

除非在它的定义之内,一个标识符的所有出现,都具有动态方面。这样的一个标识符,不仅涉及它的静态定义,还涉及到从这个定义所局域于的那个声明生成的某个对象。例如,在一个过程或类声明之内出现的一个形式参数标识符,参照这个过程或类的某个实例化的对象。

块实例

一个程序执行的组成部分,都是即子块、有前缀块、连接块和类主体的动态实例。一个块实例,被称为“局部于”直接包含它的描述文本的那个块实例。例如一个给定类的实例,局部于包含这个类声明的块实例。最外层块的实例不局部于块实例。

在任何时间,“程序顺序控制”(Program Sequence Control),首字母简写为PSC,参照在一个块实例中当前被执行的程序点;PSC被“定位”于这个程序点并被这个块实例所“包含”。进入任何块,都涉及到生成这个块的一个实例,于是PSC进入这个块实例,到达它的第一个可执行语句上。

一个块实例在任何时间,都是处在四种执行状态之一:系附(attached)、脱离(detached)、恢复(resumed)或终止(terminated)。没有在字面上给出前缀的任何类,都被定义为前缀了一个虚构(fictitious)的类,它只有一个特性即detach过程,因此所有类对象或有前缀块的实例,都拥有detach过程。在环境ENVIRONMENT中,还定义了用于调度call过程和resume过程。

  • 一个非类块实例,也就是有前缀块、子块、过程主体或连接块的实例,总是在系附状态下,这个实例被称为系附到了导致它生成的那个块上。因此一个过程体的实例,系附到包含对应函数指示符或过程语句的块实例上。非类、非过程块实例,系附到它所局部的块实例。在PSC到达非类块实例的最终的end的时候,PSC返回到紧随导致这个块实例生成的语句或表达式的程序点。
  • 一个对象,最初是在系附状态下,并被称为系附到包含对应对象生成语句的那个块实例上。一个对象,可以通过执行detach语句,进入脱离状态。通过执行call语句,可以使一个脱离状态的对象重新进入系附状态,它借此变为系附到包含这个调用语句的那个块实例上。通过执行resume语句,可以使一个脱离状态的对象进入恢复状态。不使用detachcallresume语句的一个程序执行,是一个简单的系附状态的块的嵌套结构。
  • 当PSC通过一个对象的最终end,或通过goto语句离开它的时候,这个对象进入终止状态。没有块实例系附到一个终止状态的类对象上。终止状态的对象,仍作为一个数据项而存在,它可以通过针对这个对象的包括过程和函数特性的这些特性的远程标识来引用。

每当一个块实例不复存在,局部于或系附于它的所有块实例也不复存在。一个对象的动态作用域,因而受限于它的类声明的作用域。在Simula 67最初标准中曾提到过,语言实现可以使用垃圾回收技术[7],来进一步缩减一个对象的有效寿命的跨度。一个数组声明的动态作用域,可以扩展超出包含这个声明的块实例的作用域,因为传引用调用参数传送模态适用于数组。

准并行系统

一个准并行系统[37],由一个子块或有前缀块的任何实例所标识,它包含局部的类声明。这个标识一个系统的块实例,叫做“系统头领”。最外层的标识一个系统的块实例,被称为“最外层系统”。一个准并行系统,由“组件”(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的头领),则PC的头领动态包围,并且P除了自身之外不动态包围块实例。由PC的头领X“动态合围”的块实例序列(P = Z0) → Z1 → .... → Zn-1 → (Zn = X) (n>=0),被称谓为C的“重新激活链”。除了C的头领X(脱离状态的对象)之外,这个链上的所有组件头领(恢复状态的对象),标识了生效而不运行的组件。在C成为运行的时候,在它的重新激活链上所有块也成为运行的。

组件的测序(sequencing),由detachcallresume支配。detach针对隐式指定的一个对象进行操作,而callresume显式指定所操作的对象。

测序

准并行系统的detach/resume机制,是一种协程[38]。在Simula 67最初标准中,没有恢复状态,并且没有规定call,但call通常会出现在当时的语言实现中[39]detach/call机制,相当于现在称为生成器的“半协程”,而最初标准中的resume可理解为detachcall的组合[40]。1986年修订的语言标准,增补定义了call,新增了恢复状态,并且重新定义了resume,它不可再理解为detachcall的组合。

准并行系统,被创建于进入包含局部的类声明的一个子块或有前缀块的时候,借此生成的实例成为这个新系统的头领。初始时,这个主干组件是生效的,并且是这个系统唯一的组件。

创建一个对象组件,要通过针对一个系附状态的对象,执行detach,借此PSC返回到这个对象系附到的那个块实例。这个对象进入脱离状态,并成为一个新的不生效的组件的头领,这个组件的重新激活点被定位到紧后于这个detach。如果这个对象局部于一个系统头领,则这个新的组件成为这个关联的系统的成员

通过detachcall,可以形成“半对称测序”,这只涉及到对象组件,而不区分它们是属于系统的组件还是独立组件。

  • 对于一个不生效的对象组件,通过针对它的脱离状态的头领,执行一个call,可以重新激活这个组件,借此PSC移动到它的重新激活点上。这个头领重新进入系附状态,并变成系附到包含这个call的块实例上。这个组件正式的失去了本身(作为组件)的状态。

通过detachresume,可以形成“对称组件测序”,这只涉及到属于一个准并行系统的那些组件。对立于半对称测序中的“调用者”与它的“被调用者”,在对称组件测序中的“恢复者”与它的“被恢复者”,具有完全的对称联系。

  • 对于这个系统的一个不生效的对象组件,通过针对它的脱离状态的头领,执行一个resume,可以重新激活这个组件,借此PSC移动到它的重新激活点上;这个组件的头领进入恢复状态,而这个组件变成生效的。这个系统以前生效的组件变成不生效的,并且它重新激活点被定位到紧后于这个resume;如果这个组件是一个对象组件,则它的头领进入脱离状态。
  • 对于当前生效的对象组件,通过针它的恢复状态的头领,执行一个detach,这个系统的主干组件重获生效的状态,借此PSC移动回到主干组件的重新激活点上。以前生效的组件变成不生效的,并且它重新激活点被定位到紧后于这个detach。这个组件的头领进入脱离状态。

PSC经过一个类对象的最终end的效果,除了使这个对象成为终止状态,而非脱离状态之外,相同于针对这个对象执行detach的效果。其结果是它不会得到重新激活点,并且在它已经拥有作为组件头领的状态时,失去这种状态。

程序示例

最小程序

源代码大小来衡量的话,空计算机文件是Simula 67中最小的程序,它只包含一个东西,就是虚设语句。但是,最小的程序更经常表示为空块:

Begin
End;

它开始执行并立即终止。语言缺乏来自程序的任何返回值

Hello, World!

Simula 67的经典Hello, World!示例:

Begin
    OutText ("Hello, World!");
    OutImage;
End;

OutText过程将字符串输出到缓冲区,而OutImage过程将缓冲区内容输出到标准文件,二者都定义在输出文件类OutFile中,而它是文件类File的子类。

传名调用

使用传名调用可以轻易实现Jensen设备,一个简单的例子是合计函数,它可以实现如下:

Real Procedure Sigma (k, m, n, u);
    Name k, u;
    Integer k, m, n; Real u;
Begin
    Real s;
    k:= m;
    While k <= n Do Begin s:= s + u; k:= k + 1; End;
    Sigma:= s;
End;

这个例子对受控变量k和表达式u使用了传名调用。这允许将受控变量k用于表达式u之中。由于Simula 67的for循环中受控变量,不能是传名调用的形式参数或过程标识符,故而上述代码使用了while循环。

公式可以实现为如下:

Z:= Sigma (i, 1, 100, 1 / (i + a) ** 2);

协程

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;
            ! 可尝试detachresume(X1);
        end P2;
        begin comment system 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;

这个例子程序中,有两个准并行系统S1S2S1是最外层系统,它包含了两个类声明C1C2S2嵌套入了类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类,是二叉数据结构实现:

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     
    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
end of tree;

find的过程体中出现了表达式this Tree|"java",它意图产生的值是到当前节点的引用,就是说这个节点拥有find特性的“这个”特定实例。例如,如果通过函数指示符X.find (x),来调用Xfind过程,并且X.val = x,则这个函数的结果是X自身的引用值。

抽象类

下面例子中,定义了一个抽象基础类字形Glyph,它有二个实现子类字符CharLine

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 (elements);
        Ref (Glyph) Array elements;
    Begin
        Procedure print;
        Begin
            Integer i;
            For i:= 1 Step 1 Until UpperBound (elements, 1) Do
                elements (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的有前缀块。模拟器类可在任何块上使用,而且模拟器甚至可以嵌套,比如在模拟某人做模拟的时候[41]。激活语句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

个人类PersonProcess类的子类,而它的活动,即用来浏览商店的时间,和在试衣间度过的时间,使用Process类的保持过程Hold来描述,并调用在试衣间对象中的过程,来要求和离开试衣间。正态分布随机抽签过程Normal,定义在ENVIRONMENT类中,它的最后的参数,必须是指定一个伪随机数的一个整数。主程序创建所有对象,并激活所有Person对象,从而将他们放置入事件队列之中。主程序在程序终止前,保持100分钟的模拟时间。

参见

注释

  1. 1.0 1.1 1.2 SIMULA Standards Group. SIMULA Standard (PDF). 1986 [2022-03-23]. 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).
     
  2. 2.0 2.1 Portable Simula Revisited. [2022-03-15]. 
  3. 3.0 3.1 GNU Cim. [2022-04-02]. 
  4. Kristen Nygaard; Ole-Johan Dahl. The Development of the Simula Languages (PDF). 1978 [2022-03-14]. 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. Barbara Liskov. A history of CLU (PDF). 1992 [2022-04-27]. 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, ……. 
  6. 6.0 6.1 Ole-Johan Dahl. The Birth of Object Orientation: the Simula Languages (PDF). 2001 [2022-04-13]. On the other hand, if a procedure P is specified as virtual in a class C the binding scheme is semi-dynamic. Any call for P occurring in C or in any subclass of C will bind to that declaration of P 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 procedure P may, at the prefix level of C, be postponed to occur in any subclass of C. 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 for C 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.
     
  7. 7.0 7.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. 
  8. 8.0 8.1 Ole-Johan Dahl. The Birth of Object Orientation: the Simula Languages (PDF). 2001 [2022-04-13]. 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.
     
  9. 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. 
  10. C. A. R. Hoare. Record Handling (PDF). ALGOL Bulletin no. 21. 1965 [2022-03-14]. 
  11. Jan Rune Holmevik. Compiling Simula. Oslo, Norway: Institute for Studies in Research and Higher Education. 1994. 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.
     
  12. 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]. 
  13. Ole-Johan Dahl; Bjørn Myhrhaug; Kristen Nygaard. SIMULA 67 Common Base Language (PDF). Norwegian Computing Center. 1968, 1970 [2022-02-13]. 
  14. Swedish standard SS 63 61 14 (PDF). [2022-04-14]. 
  15. Alan Kay. The Early History of Smalltalk. [2022-04-11]. 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.
     
  16. Carl Hewitt; Peter Bishop, Richard Steiger. A Universal Modular Actor Formalism for Artificial Intelligence (PDF). IJCAI. 1973 [2022-04-11]. Alan Kay whose FLEX and SMALLTALK machines have influenced our work. Alan emphasized the crucial importance of using intentional definitions of data structures and of passing messages to them. This paper explores the consequences of generalizing the message mechanism of SMALLTALK and SIMULA-67; ……. 
  17. 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. 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]. 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. 
  18. 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.
     
  19. 19.0 19.1 Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. A switch declaration defines the set of values of the corresponding switch designators. These values are given one by one as the values of the designational expressions entered in the switch list. With each of these designational expressions there is associated a positive integer, 1, 2, ..., obtained by counting the items in the list from left to right. The value of the switch designator corresponding to a given value of the subscript expression ( …… ) is the value of the designational expression in the switch list having this given value as its associated integer. 
  20. Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. Every block automatically introduces a new level of nomenclature. This is realized as follows: Any identifier occurring within the block my through a suitable declaration ( …… ) be specified to be local to the block in question. This means ⒜ that the entity represented by this identifier inside the blocks has no existence outside it and ⒝ that any entity represented by this identifier outside the block is completely inaccessible inside the block.
    Identifiers (except those representing labels) occurring within a block and not being declared to this block will be non-local to it, i.e. will represent the same entity inside the block and in the level immediately outside it. A label separated by a colon from a statement, i.e. labelling that statement, behaves as though declared in the head of the smallest embracing block, i.e. the smallest block whose brackets begin and end enclose that statement. In this context a procedure body must be considered as if it were enclosed by begin and end and treated as a block.
    Since a statement of a block may again itself be a block the concepts local and non-local to a block must be understood recursively. Thus an identifier, which is non-local to a block A, may or may not be non-local to the block B in which A is one statement.
     
  21. 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).
     
  22. 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.
     
  23. 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. 
  24. 24.0 24.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.
     
  25. D. A. Turner. Some History of Functional Programming Languages (PDF). in an invited lecture TFP12, St Andrews University. 12 June 2012 [2022-05-04]. 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.
     
  26. 26.0 26.1 Ole-Johan Dahl; Bjørn Myhrhaug. The Simula Implementation Guide (PDF). 1967, 1973 [2022-04-17]. 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. 
  27. Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. Name replacement (call by name). Any formal parameter not quoted in the value list is replaced, throughout the procedure body, by the corresponding actual parameter, after enclosing this latter in parentheses wherever syntactically possible. Possible conflicts between identifiers inserted through this process and other identifiers already present within the procedure body will be avoided by suitable systematic changes of the formal or local identifiers involved. 
    D. A. Turner. Some History of Functional Programming Languages (PDF). in an invited lecture TFP12, St Andrews University. 12 June 2012 [2022-05-04]. 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.
     
  28. Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. Any occurrence of the procedure identifier within the body of the procedure other than in a left part in an assignment statement denotes activation of the procedure. 
  29. Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. Values of function designators. For a procedure declaration to define the value of a function designator there must, within the procedure declaration body, occur one or more explicit assignment statements with the procedure identifier in a left part; at least one of these must be executed, and the type associated with the procedure identifier must be declared through the appearance of a type declarator as the very first symbol of the procedure declaration. The last value so assigned is used to continue the evaluation of the expression in which the function designator occurs. 
  30. Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. Parameter delimiters. All parameter delimiters are understood to be equivalent. No correspondence between the parameter delimiters used in a procedure statement and those used in the procedure heading is expected beyond their number is the same. Thus the information conveyed by using the elaborate ones is entirely optional. 
  31. Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. Value assignment (call by value). All formal parameters quoted in the value part of the procedure declaration heading are assigned the values ( …… ) of the corresponding actual parameters, these assignments being considers as being performed explicitly before entering the procedure body. The effect is as though an additional block embracing the procedure body were created in which these assignments were made to variables local to this fictitious block with types as given in the corresponding specifications ( …… ). As a consequence, variables called by value are to be considered as nonlocal to the body of the procedure, but local to the fictitious block ( …… ). 
  32. 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 …… 
  33. 33.0 33.1 Kristen Nygaard; Ole-Johan Dahl. The Development of the Simula Languages (PDF). 1978 [2022-03-14]. 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. 
  34. Ole-Johan Dahl. The Birth of Object Orientation: the Simula Languages (PDF). 2001 [2022-04-13]. 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. 
  35. Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. Function designators define single numerical or logical values which result through the application of given sets of rules defined by a procedure declaration ( …… ) to fixed sets of actual parameters. 
  36. Peter Naur; et al. Revised Report on the Algorithmic Language Algol 60. [2022-04-14]. A procedure statement serves to invoke (call for) the execution of a procedure body ( …… ). Where the procedure body is a statement written in Algol the effect of this execution will be equivalent to the effect of performing the following operations on the program at the time of execution of the procedure statement. 
  37. Kristen Nygaard; Ole-Johan Dahl. The Development of the Simula Languages (PDF). 1978 [2022-03-14]. 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. 
  38. Kristen Nygaard; Ole-Johan Dahl. The Development of the Simula Languages (PDF). 1978 [2022-03-14]. 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.
     
  39. Ole-Johan Dahl; Bjørn Myhrhaug. The Simula Implementation Guide (PDF). 1967, 1973 [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. 
  40. 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. ……
    Let X and Y be objects, generated by a "master program" M. Assume that M issues a call (X), thereby invoking an "active phase" of X, terminated by a detach operation in X; and then issues a call (Y), and so forth. In this way M may act as a "supervisor" sequencing a pattern of active phases of X, 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 operation resume (Y), executed by X, combines an exit out of X (by detach) and a subsequent call (Y), thereby bypassing M. Obligation to return to M is transferred to Y.
     
  41. Jaroslav Sklenar. INTRODUCTION TO OOP IN SIMULA. 1997 [2022-02-13]. The system class Simulation introduces the notion of time. It means that if nested, there will be other local (nested) times. 

延伸阅读

外部链接