Modula-3项目始于1986年11月,当时莫里斯威尔克斯给Niklaus Wirth写了一些关于Modula新版本的想法。 Wilkes在此之前一直在DEC工作,并已回到英国并加入Olivetti的研究战略委员会。 Wirth已经转到Oberon,但是在Modula的名字下威尔克斯的团队继续发展并没有问题。语言定义于1988年8月完成,并于1989年1月更新。DEC和Olivetti的编译器很快就完成了,随后的第三方实现。
它的设计深受当时SRC和Acorn计算机研究中心(ARC,后来ORC当Olivetti收购Acorn时)使用的Modula-2 +语言的影响,这是用于操作系统的语言编写了DEC Firefly多处理器VAX工作站,其中编写了用于Acorn C的Acorn编译器和ARC的ARM模块执行库(CAMEL),用于基于ARM的Acorn Archimedes系列ARM计算机的ARX操作系统项目。正如修订后的Modula-3报告所述,该语言受到Mesa,Cedar,Object Pascal,Oberon和Euclid等其他语言的影响。
在20世纪90年代,Modula-3作为教学语言获得了相当可观的货币,但它从未广泛用于工业用途。对此有所贡献的可能是DEC,一个关键的Modula-3支持者(特别是在1998年DEC出售给康柏之前不再有效地维持它)的消亡。无论如何,尽管Modula-3的简单性和强大功能,似乎很少需要使用面向对象编程的程序化编译语言。一段时间以来,一个名为CM3的商业编译器由DEC SRC之前的主要实现者之一维护,他在DEC被出售给Compaq之前被聘用,一个名为Reactor的集成开发环境和一个可扩展的Java虚拟机(以二进制和源格式授权以及由Critical Mass,Inc.提供,但该公司在2000年停止了活动,并将其产品的一些来源提供给elego Software Solutions GmbH。 Modula-3在大学里教授,主要是比较编程语言课程,其教科书已绝版。从本质上来说,Modula-3的公司支持者是elego Software Solutions GmbH,该公司继承了来自Critical Mass的资源,并且此后以源代码和二进制形式发布了CM3系统的多个版本。 Reactor IDE在几年之后就已经开放源代码,并且新的名称为CM3-IDE。 2002年3月,elego还接管了另一个主动Modula-3发行版PM3的存储库,直到当时保留在蒙特利尔高等理工学院,但后来由于HM3的工作而继续改进,直到它被废弃为止。
语言的语法一个常见例子是Hello world程序。
Modula-3中的所有程序都至少有一个模块文件,而大多数程序还包含一个客户端用来访问模块数据的接口文件。 像其他语言一样,Modula-3程序必须导出一个主模块,它可以是一个名为Main.m3的文件,也可以是一个文件可以调用EXPORT来导出主模块。
建议模块文件名称与实际模块名称相同,但编译器只会在不同的情况下提醒您。
语法中的其他约定包括命名接口T的导出类型,因为类型通常由它们的全名来限定,所以在名为Foo的模块内的类型T将被命名为Foo.T. 这有助于可读性。 另一个类似的约定是在上面的OOP示例中命名公共对象Public。
首先,所有编译单元都是INTERFACE或实现MODULE,具有一种或另一种风格。一个接口编译单元,从关键字INTERFACE开始,定义常量,类型,变量,例外和过程。实现模块以关键字MODULE开头,提供实际代码以及实现接口所需的任何其他常量,类型或变量。默认情况下,实现模块将实现相同名称的接口,但是模块可以明确地将EXPORT输出到不具有相同名称的模块。例如,主程序为Main接口导出一个实现模块。
任何编译单元都可以导入其他接口,但禁止循环导入。 这可以通过从执行MODULE执行导入来解决。 使用FROM模块IMPORT Item [,Item] *语法可以导入导入模块中的实体,而不仅仅是模块名称:
通常,只导入接口,并使用'点'符号访问接口内的项目(类似于访问记录中的字段)。一个典型的用法是为每个接口定义一个数据结构(记录或对象)以及任何支持过程。在这里主类型将得到名称'T',并且使用MyModule.T 中的一个。
如果导入的模块与模块内的其他实体之间发生名称冲突,则保留字AS可用于IMPORT CollidingModule AS X;
某些功能被认为是不安全的,编译器不能再保证结果是一致的(例如,与C编程语言接口时)。前缀INTERFACE或MODULE前面的关键字UNSAFE可用于告诉编译器启用该语言的某些低级功能。例如,一个不安全的操作是绕过使用LOOPHOLE的类型系统将一个整数的位复制到一个浮点实数。
导入不安全模块的接口本身不安全。 安全接口可能由不安全的实现模块导出。这是连接到外部库时的典型用法,其中构建了两个接口(一个不安全,另一个安全)。
通用接口及其相应的通用模块,在INTERFACE或MODULE关键字前加上GENERIC,并将其他接口作为形式参数。 因此(像C ++模板一样)可以很容易地定义和使用抽象数据类型,但与C ++不同的是,粒度在模块级别。 接口作为实际参数传递给通用接口和实现模块,编译器将生成具体模块。
例如,可以定义GenericStack,然后使用IntegerElem或RealElem等接口或甚至与对象的接口对其进行实例化,只要这些接口中的每一个都定义了通用模块所需的属性即可。
注意:裸类型INTEGER或REAL不能使用,因为它们不是模块,泛型系统基于使用模块作为参数。相比之下,在C ++模板中,将使用裸类型。
文件: IntegerElem.i3
文件:GenericStack.ig
文件:GenericStack.mg
文件:IntegerStack.i3
文件:IntegerStack.m3
任何标识符都可以追溯到它的起源地点,而不像其他语言的“包含”特征。 编译单元必须使用IMPORT语句从其他编译单元导入标识符。 即使枚举也使用与访问记录字段时使用的'点'符号相同的符号。
Modula-3支持在运行时分配数据。有两种内存可以分配TRACED和UNTRACED,不同之处在于垃圾收集器是否可以看到它。NEW()用于分配这两类内存中的任何一个的数据。在UNSAFE模块中,DISPOSE可用于释放未交叉的内存。
面向对象编程技术可用于Modula-3,但不需要使用它们。Modula-3(模块,泛型)中提供的许多其他功能通常可代替面向对象。
对象支持有意保留其最简单的条款。OBJECT声明引入了一个对象类型(在其他面向对象的语言中称“类”),尽管对象类型是引用类型,但与Modula-3中的RECORD不同 (类似于C中的结构)。按照惯例,导出的类型通常被命名为T,并创建一个单独的“公共”类型来公开方法和数据。 例如:
异常处理基于TRY ... EXCEPT块系统,它变得很常见。除了Delphi,Python ,Scala和Visual Basic.NET之外,其他语言中尚未采用的一个特性是[EXCEL]构造定义了一种switch语句形式,每种语言都有 作为它自己的EXCEPT子句中的一个例子可能的例外。Modula-3还支持LOOP ... EXIT ... END结构,该结构循环直到出现EXIT,这个结构等同于TRY ... EXCEPT子句中的简单循环。
该语言支持使用多线程,以及线程之间的同步。运行时库(m3core)中有一个名为Thread的标准模块,它支持使用多线程应用程序。实际上,Modula-3运行时可能会使用单独的线程来执行垃圾收集等内部任务。
内置数据结构MUTEX用于同步多个线程,并保护数据结构免受可能的损坏或竞争条件的同时访问。LOCK和相应的UNLOCK语句锁定和解锁MUTEX。MUTEX是一个对象,因此可以从中派生出其他对象。
例如,在libm3库的I / O部分,读写器(Rd.T和Wr.T)从MUTEX派生,并且在访问或修改任何内部数据(如缓冲区)之前锁定自己。