Modula-3
Modula-3是一种系统编程语言，它是叫做的升级版本的Modula-2的后继者。虽然它已经在研究界有了影响力（受其影响的语言有Java、C#和Python），但未能在工业上被广泛采用。它是在上世纪80年代末由在数字设备公司（DEC）（SRC）和Olivetti研究中心（ORC）的、James Donahue、Lucille Glassman、Mick Jordan（之前在Olivetti软件技术实验室工作）、Bill Kalsow和设计。
Modula-3的主要特点，是保持系统编程语言的强力，同时具有简单性和安全性。Modula-3意图延续Pascal的类型安全传统，同时为实际编程引入新构造。特别是Modula-3添加了如下支持：泛型编程（类似于模板）、多线程、异常处理、垃圾回收、面向对象编程、部份披露和不安全代码显式标记。Modula-3的设计目标，是以非常基本的形式，实现指令式编程语言的大部份重要的现代特征。因此省略了涉嫌危险和复杂的特征，如多重继承和运算符重载。
Modula-3项目始于1986年11月，当时莫里斯·威尔克斯向尼克劳斯·维尔特写信，提出了一些关于Modula新版本的想法。威尔克斯在此之前一直在DEC工作，他回到英格兰并加入了Olivetti的研究策略委员会。Wirth已经转移到了Oberon，但Wilkes的团队在Modula名下继续开发没有任何问题。语言定义于1988年8月完成，并于1989年11月更新了版本。DEC和Olivetti的编译器很快就出现了，随后又有了第三方实现。
它的设计受到和Acorn计算机研究中心（ARC，在Olivetti收购Acorn之后叫做ORC）在语言上的工作的很大影响，是编写多处理器VAX工作站的操作系统的语言，还是在基于ARM的系列计算机的项目中，ARC编写用于Acorn C和模块执行库（CAMEL）的Acorn编译器的语言。正如修订的Modula-3报告所述，该语言演化自Mesa、Modula-2、Cedar和，还受到其他语言的影响如：Object Pascal，Oberon和。
在20世纪90年代，Modula-3作为一种教学语言获得了可观的传播，华盛顿大学在1994年发行的微内核操作系统是用Modula-3开发的，但它从未广泛用于工业用途。造成这种情况的原因，可能是Modula-3的关键支持者DEC的消亡（特别是在1998年DEC被出售给康柏之前就不再有效地维护它了）。无论如何，尽管Modula-3有着简单性和强大功能，似乎当时对有限实现了面向对象编程的过程式编译语言的需求很少。
Critical Mass公司曾在一段时间内提供了一个名为CM3的商业编译器，它由以前DEC SRC的在DEC被出售给Compaq之前雇用的一个主要实现者维护，和叫做Reactor的一个集成开发环境以及可扩展的Java虚拟机（以二进制和源格式许可发行并可用Reactor来构建）。但该公司在2000年停止了活动，并将其产品的一些源代码提供给了elego软件解决方案有限公司。
基本上，Modula-3的唯一企业支持者是elego软件解决方案有限公司，它继承了Critical Mass的资源，并且已经以源代码和二进制形式发布了几个版本的CM3系统。Reactor IDE在几年后才开源发布，新的名称是CM3-IDE。2002年3月，elego还接管了此前由蒙特利尔工程学院维护的另一个活跃的Modula-3发行版PM3的存储库，在此后几年间以HM3名义进行了持续改进，直至最终被淘汰。
Modula-3是文档记录了语言特征演化的少见语言之一，在《用Modula-3系统编程》中，收录了设计者对四个设计要点的讨论：结构等价与名称等价、子类型规则、泛型模块和参数模态。Modula-3现在主要是在大学中的比较编程语言课程中教授，其教科书已绝版。
Modula-3中所有的程序至少具有一个模块文件，而大多数程序还包括一个接口文件，客户端使用它来访问来自模块的数据。语言语法的一个常见示例是Hello world程序：
MODULE Main;  BEGIN END Main.
与其他语言一样，Modula-3程序必须有导出codice_1接口的实现模块，如上述示例中实现模块缺省导出了同名的接口，它可以处在名为Main.m3的文件中；或者是通过codice_2导出codice_1接口的实现模块，比如：
MODULE HelloWorld EXPORTS Main;  BEGIN END HelloWorld.
建议这个模块所在的文件的名字与实际模块名字相同，当它们不同时编译器只是发出一个警告。
Modula-3的设计者认为：始自BCPL的C语言家族，其优美在于以适度的代价得到了相对汇编语言的巨大飞跃，但它们接近于目标机器的低层是天然有危险性的；其中的衍生语言C++，通过增加对象丰富了C，但它放弃了C的最佳优点简单性，却没有消除它最差缺点即低层编程模型。另一个极端是LISP语言家族，它们有着混合了lambda演算和配对函数理论的，但它们趋于难以高效实现，因为在编程模型中值的统一对待，招致了所有的值都由指针统一表示的运行时间系统；这个家族的语言的良好实现避免了多数代价而能用于系统编程，但它们普遍秉性仍旧向往堆分配而非栈分配，这种运行时间系统经常将它们孤立于封闭环境中，而不能容纳用其他语言写的程序。
Modula-3的设计者认为：ALGOL语言家族处在这两个极端之间，它的现代代表包括Pascal、Ada、Modula-2和Modula-3，这些语言拥有的编程模型反映了随机存取机在工程上的约束，隐藏了任何特定于机器的细节。它们放弃了LISP家族的优美和数学对称性，使得无须特殊技巧就可能高效的实现，并且避免了C家族的多数危险和依赖机器的特征。它们都有强类型系统，其基本想法是把值空间划分成类型，限制变量持有单一类型的值，并且限制运算应用于固定类型的运算数。
Modula-3承袭了ALGOL家族传统的强类型，并且为了使类型系统尽可能的统一，采用了如下原则：首先，类型或目标类型确定是没有歧义的，所有的表达式的类型由它的子表达式来确定，而非由它的使用来确定。其次，没有自动转换。第三，可赋值性和类型兼容性，是依据单一的在语法上用codice_4指定的子类型关系来定义的，它具有如下性质：如果codice_5是codice_6的子类型，则所有的codice_5的成员都是codice_6的成员，子类型关系是自反和传递的；子类型关系是处理具有继承的对象所需要的，但也能用于确定常规类型的兼容性规则。
Modula-3委员会坚持一个自称为“复杂度预算”的设计原则：在五十页内将语言准确而易读的描述出来，为此只容纳最有用的特征。精选出来的特征直接针对两个主要目标：接口、对象、泛型和线程，提供有助于建造大型程序的基础抽象模式，不安全代码的显式标记、自动垃圾收集和异常，有助于让程序更加安全和健壮。这些特征中任何一个都没有特殊的新颖性，但是组合起来是简单而强力的。
一个典型的不安全运行时间错误，是释放仍可由活跃引用（悬空指针）触及的数据结构。避免这个问题的唯一可靠方式，是不再触及存储的自动释放，或称为垃圾收集。Modula-3因而提供了有跟踪的引用，它类似于Modula-2的指针，除了它们所指向的存储被保存在有跟踪的堆之中之外，在这里它们将在到它们的引用都消失时自动释放。垃圾收集的另一个巨大利益是简化了接口，没有垃圾收集，接口就必须规定客户或实现是否有责任释放每个分配的引用，和在什么条件下可以安全的去这么做。
异常是一次退出多层作用域的控制结构。一个异常被重复的发起退出当前活跃的作用域，直到找到给这个异常的处理器，并将控制权移交给这个处理器，如果没有处理器，则计算以某种依赖于系统的方式终止，比如进入调试器。在Modula-3中，codice_9和codice_10语句的语义，分别使用叫做codice_11和codice_12的异常来定义。Modula-3的设计者认为：语言实现应当以除了返回异常和退出异常之外的异常为代价，加速正常的结果产出。为每个引发的异常花费一千条指令，来为每个过程节约一条指令都是合理的。
一个Modula-3程序规定了一个计算，它作用在一序列的叫做地点（location）的数字元件之上。变量是地点的一个集合，它依据这个变量的类型所确定的约定，表示一个数学上的值。如果一个值可以由类型codice_5的某个变量来表示，则称谓这个值是codice_5的一个成员，并且codice_5包含这个值。
为一个变量、类型、过程、或异常指定一个被称为的作为名字。一个声明应用于其上的程序区域，叫做这个声明的作用域。作用域是可以嵌套的。一个标识符的含义，由这个标识符在其中声明的最小的包围作用域来确定。
类型声明有如下形式：，这里的codice_5是一个标识符，而codice_6是一个类型或类型表达式。在需要类型的各种地方，通常允许类型表达式。
变量声明有如下形式：，这里的codice_18是一个标识符，codice_5是除了开放数组之外的一个非空类型，而codice_20是一个表达式。它声明了codice_18是类型codice_5的一个变量，其初始值是codice_20的值。codice_24和codice_25任何一个都可省略，但二者不能都省略。如果省略了codice_5，它采用codice_20的类型。如果省略了codice_20，初始值是类型codice_5的任意值。如果二者都存在，codice_20必须可赋值给codice_5。初始值是一种简写，等价于在随后的块的可执行部份开始处插入赋值codice_32，如果多个变量有初始值，按它们声明的次序插入它们的赋值。形式，是的简写。
声明有如下形式：，这里的codice_18是一个标识符，codice_5是一个类型，而codice_35是一个常量表达式。它声明codice_18为具有类型codice_5和值codice_35的一个常量。codice_25可以省略，在这种情况下codice_18的类型是codice_35的类型。如果codice_5存在，则它必须包含codice_35。
Modula-3的类型系统使用，而非Modula-2的即类型构造子的每次出现产生一个新类型。在结构等价中，在如果两个类型的定义在展开的时候，也就是在所有常量表达式都被替换为它们的值，并且所有类型名字都被替代为它们的定义的时候，变成相同的，则这两个类型是相同的。在递归数据类型的情况下，这个展开是部份展开的无穷极限。
有三种序数类型：枚举、子范围和整数类型，预定义了如下序数类型：codice_44、codice_45、codice_46（如同子范围codice_47）、codice_48（枚举codice_49）和codice_50（包含至少256个元素表示ISO-Latin-1代码的枚举）。整数和枚举元素合起来叫做序数值。序数值codice_51如果是整数或扩展精度整数，则codice_51的基础类型分别是codice_44或codice_45，否则codice_51的基础类型是包含它的那个唯一性的枚举类型。两个序数如果有相同的值则二者相等。
有三种浮点类型：codice_56、codice_57和codice_58，这些类型的属性规定在对应的必要接口中。两个浮点数如果定义它们的底层实现相同则二者相等。
一个引用值要么是codice_59，要么是一个叫做所引用者（referent）的变量的地址。预定义了如下引用类型：codice_60，它包含所有的有跟踪的引用，codice_61，它包含所有的无跟踪的引用，和codice_62，它只包含codice_59。Modula-3支持在运行时间的数据分配。分配操作有如下形式：，这里的codice_5是除了预定义的codice_60、codice_61或codice_67之外的引用类型。两个引用如果寻址相同的地点则二者相等。
记录是叫做这个记录的字段的命名变量的一个序列，记录类型的声明有如下形式：，在这里的类型表达式中，codice_68是类型构造子，而它的实际参数是字段声明的一个列表codice_69，其中每个字段都有如下形式：，这里的字段名字codice_70是一个标识符，而字段类型codice_71是除了开放数组之外的非空类型，而字段缺省值codice_72是一个常量表达式。形式，是的简写。两个记录如果有相同的字段，并且对应的字段都相等则二者相等。
在Modula-3中的对象非常类似于Simula 67中的对象：它们总是引用，它们拥有数据字段和方法二者，并且它们有着单一继承而非多重继承。预定义了如下对象类型：codice_73，它是没有字段或方法的有跟踪的对象类型，和codice_74，它是没有字段或方法的无跟踪的对象类型。
是一个名字，它指示某个给定引用类型的未知子类型。预定义了两个：codice_75和codice_76，它们分别表示文本串和互斥信号量，它们的属性分别规定于必要接口codice_77和codice_78之中。
数组是叫做这个数组的元素的组成变量的有索引的搜集。有两种数组类型，固定的和开放的。固定数组的长度是在编译时间确定的，开放数组的长度是在运行时间分配确定的，这个长度此后不能改变。两个数组如果有相同的长度，并且对应的元素都相等则二者相等。
包装类型的变量出现在记录、对象或数组中，占据指定数量的位元，并毗邻于前导的字段或元素紧压打包。包装类型的声明有如下形式：，这里的codice_79是一个基础类型，而codice_80是整数取值的常量表达式。
集合是取自某个序数类型的值的搜集。集合类型声明有如下形式：，这里的基础类型codice_79是一个序数类型。两个集合如果有相同的元素则二者相等。
不包含值的一个类型是空的，例如codice_82是一个空类型。空类型可以用来建造非空类型，比如codice_83。声明一个空类型的一个变量是静态错误。
所有的都有一个唯一的类型，但是一个值可以是很多类型的一个成员，例如值codice_84是codice_85和codice_44二者的成员，因此论述“一个值的类型”将会是有歧义的。短语“codice_87的类型”，意味着“表达式codice_87的类型”；然而短语“codice_87是codice_5的成员”，意味着“codice_87的值是codice_5的成员”。但在有一种情况下，一个值可以称为有着一个类型：所有的对象或有跟踪的引用值，包括了一个类型代码，它叫做这个引用值的分配类型。分配类型通过codice_93语句来测试。
语言规定提供了类型运算codice_94、codice_95和codice_96，分别返回变量codice_87或者类型codice_5的那些变量的位元数目、8位字节的数目和可寻址地点的数目。在所有情况下，codice_87必须是指示符，而codice_5必须不是开放数组类型，指示符codice_87只在它的类型是开放数组的时候求值。
枚举类型声明有如下形式：，这里的codice_18是各不相同的标识符，类型codice_5是codice_80个值的有序集合，表达式codice_105指示这个类型在递增次序下的第codice_106个值，空枚举codice_107是允许的。
子范围类型声明有如下形式：，这里的codice_108和codice_109是有相同的基础类型的两个序数值，codice_5的值是从codice_108到codice_109含二者所有的值，它们必须是常量表达式，如果codice_108超过codice_109，则子范围是空的。
每个不同的枚举类型介入新的一组值，而子范围类型重复使用底层类型的值。例如：
TYPE
这里的codice_115和codice_116是相同类型，因为它们有相同的展开定义。codice_117和codice_118也是相同的类型，因为codice_119。类型codice_115和codice_117却是不同的，尽管它们包含相同的值，但是codice_115的展开定义是枚举，而codice_117的展开定义是子范围。类型codice_124是第三个类型，它的值codice_125和codice_126无关于值codice_127和codice_128。 语言规定提供了支持序数类型的一些类型运算：对于序数类型codice_5，codice_130返回在codice_5中元素的数目，codice_132返回codice_5的最小值，codice_134返回codice_5的最大值。codice_136将一个枚举的元素codice_137，转换成表示它在枚举次序中所处位置的整数，如果元素的类型是枚举codice_5的子范围，结果是元素在codice_5内的位置，而非在子范围内。codice_140将表示在枚举类型codice_5中位置的整数codice_106，转换成在这个枚举中此位置上的那个元素，如果codice_5是枚举类型的子范围，结果是在源出枚举类型的位置codice_106上的元素，而非在子范围内。如果codice_80是类型codice_5的一个整数，则有平凡的：codice_147。
固定数组类型声明有如下形式：，这里的索引类型codice_148是序数类型，而元素类型codice_149是除了开放数组之外的任何类型。开放数组类型声明有如下形式：，这里的元素类型codice_149是任何类型。
数组类型codice_5的值，是元素类型为codice_149的数组；对于固定数组类型，这个数组的长度是索引类型codice_148的元素数目；对于开放数组类型，这个数组的长度是任意的；开放数组的索引类型是codice_44子范围codice_155，这里的codice_80是这个数组的长度。开放数组类型只能用作形式参数的类型，引用类型的所引用者，另一个开放数组的元素类型，或作为数组构造子中的类型。
多维数组的形状是它每一维的长度的序列。更精确的说，一个数组的形状是它的长度跟随着任何它的元素的形状，非数组的形状是空序列。数组如果有相同的类型和形状，则它们是可赋值的。如果赋值的要么来源要么目标是开放数组，则需要运行时间检查。形如的表达式，是的简写。
如果codice_157有数组类型codice_5，则codice_159指示codice_157的一个指定元素，它在数组中的位置对应于codice_106在索引类型中位置。形如codice_162的表达式，是codice_163的简写。索引的解释由一个数组的类型确定，而非它的值；数组赋值改变数组变量的值，而非它的类型。例如：
VAR
这里在codice_157或codice_165做元素值变更之前，codice_166为codice_167，尽管codice_168而codice_169。
可以使用codice_170，得到一个固定数组类型的索引类型中的元素数目，使用codice_171和codice_172，分别得到一个固定数组类型的索引类型的最小元素和最大元素。可以使用codice_173，得到一个数组的索引类型中的元素数目，使用codice_174和codice_175，分别得到一个数组的索引类型的最小元素和最大元素，在这种情况下，表达式codice_157只在它指示一个开放数组的时候求值。
一个引用类型要么是有跟踪的要么是无跟踪的。当到已分配的一段存储的所有的有跟踪的引用都消失时，系统对这段存储进行垃圾回收。有跟踪的引用类型以如下形式来声明：，这里的codice_71是任何类型。codice_5的值是到类型codice_71的变量的有跟踪的引用，codice_71叫做codice_5的所引用类型。无跟踪的引用类型以如下形式来声明：，这里的codice_71是任何无跟踪的类型（这个限制在不安全模块中解除）。
两个引用类型如果都是有跟踪的或都是无跟踪的，那么它们有相同的引用类。一个一般性的类型是有跟踪类型的条件为，它是有跟踪的引用类型，其任何字段类型是有跟踪类型的记录类型，其元素类型是有跟踪类型的数组类型，或其底层未包装类型是有跟踪类型的包装类型。 在有跟踪的和无跟踪的二者情况下，关键字codice_183可选的可以前导上codice_184，这里的codice_165是叫做铭牌（brand）的文本常量。铭牌用来区分原本上相同的类型，它们没有其他语义效果。在一个程序中所有铭牌都必须是唯一性的。如果codice_186出现而codice_165缺席，系统自动的为codice_165提供一个唯一的值。
分配操作返回codice_5的所引用类型的一个新分配的变量的地址，如果codice_5是对象类型，则返回到有配对的方法套件的一个新分配的数据记录的引用。codice_191返回的引用不同于所有的现存引用。这个新引用的分配类型是codice_5。如果codice_5的所引用类型为空则是一个静态错误。如果codice_5是到有codice_195个开放维度的数组的引用，codice_196操作有如下形式：，这里的这些codice_80是指定新数组在它的前codice_195个维度上的长度的整数取值表达式。
所有的对象类型和有跟踪的引用类型（包括codice_67）都有一个关联的整数代码。不同的类型有不同的代码。给一个类型的代码对程序的任何单一执行都是常量，但对不同的执行可以不同。类型运算codice_200，返回类型codice_5的这个代码，而codice_202，返回引用codice_203的分配类型的这个代码。如果codice_5是codice_60，或者不是对象类型或有跟踪的引用类型，则是一个静态错误。类型运算codice_206，测试codice_87是否为codice_5的成员，这里的codice_5必须是对象类型或有跟踪的引用类型，而codice_87必须可赋值给codice_5。
规定产生一个值或变量的一个计算。所有的表达式都有一个静态确定的类型，它包含这个表达式可以产生的所有的值。在语法上，一个表达式要么是一个运算数，要么是应用于自身也是表达式的实际参数的一个运算。运算数是、或类型。通过递归的求值一个运算的实际参数并应用这个运算，来求值一个表达式。实际参数的求值次序，对除了短路求值的codice_212和codice_213之外的所有运算都是未定义的。
对一个过程的调用，在这个过程是返回一个结果的函数过程的时候，是称为函数应用的一个表达式，这个表达式的类型是过程的结果类型。
Modula-3语言规定提供了前缀算术运算：codice_214、codice_215，中缀算术运算：codice_214、codice_215、codice_218、codice_219、codice_220、codice_221，数值函数运算：codice_222、codice_223、codice_224、codice_225、codice_226、codice_227、codice_228、codice_229，关系运算：codice_230、codice_231、 codice_232、codice_233、codice_234、codice_235，逻辑运算：codice_236、codice_237、codice_238，文本串接运算：codice_239，内存分配运算：codice_240，集合运算：并集codice_214、差集codice_215、交集codice_218、对称差集codice_219和隶属关系测试codice_245，它在序数codice_246是集合codice_247的元素的时候返回codice_167。
表达式可建构自如下：、实数文字、和。集合、数组和记录有构造子表达式：
表达式是一般性的表达式类的子集，所要求的限制使得可以静态的求值这个表达式。在常量表达式中，除了codice_191、解引用（显式的或隐式的）、codice_278、codice_279、codice_280、codice_281、codice_282和codice_283之外的所有运算都是合法的，唯独可运用的过程，是在提供无符号字运算的codice_284接口中的函数。变量在常量表达式中，只能作为给codice_285、codice_286、codice_287、codice_94、codice_95或codice_96的实际参数出现，并且这个变量必须不是开放数组类型的。文字和顶层过程常量在常量表达式中是合法的。
产生变量的表达式叫做指示符（designator）。常量表达式永远不是指示符。指示符的类型是它产生的变量的类型。一个指示符依赖于上下文，可以指示要么一个变量，要么这个变量的值。比如，它作为赋值的左值时是变量，作为右值时是这个变量的值。一些指示符是只读的，它们不能用在可能改变这个变量的值的上下文中，并非只读的指示符就是可写的指示符。
一个标识符是可写的指示符的条件为，它被声明为变量，是codice_291或codice_292形式参数，codice_93或codice_294语句的局部变量，或绑定到可写指示符的codice_295局部变量。一个标识符是只读的指示符的条件为，它是codice_296形式参数，codice_297语句的局部变量，或绑定到非指示符或只读的指示符的codice_295局部变量。只有如下运算可以产生指示符：
使用codice_368指示codice_5是codice_6的子类型，也就是codice_6是codice_5的超类型。子类型规则是：如果codice_368，则类型codice_5的所有值，都是类型codice_6的值，反过来则不成立。
对于序数类型codice_5和codice_6，codice_368的条件为，它们拥有相同的基础类型，并且所有的codice_5的成员都是codice_6的成员。就是说序数类型上的子类型，反映了在值集合上的子集关系。
对于数组类型，一个数组类型codice_259是一个数组类型codice_382的子类型的条件为，它们有相同的最终元素类型，相同的维度数，并且对于每个维度，要么二者都是开放的，要么codice_259是固定的而codice_382是开放的，要么它们都是固定的并有着相同的大小。
对于过程类型，codice_368的条件为，它们除了形式参数名字、缺省值和codice_386集合之外是相同的，并且codice_5的codice_386集合包含在codice_6的codice_386集合中。codice_307是所有的过程类型的一个成员。
对于包装类型，codice_392和codice_5有相同的值，也就是说：codice_394并且codice_395。
对于集合类型，codice_396的条件是codice_397，就是说集合的子类型规则简单的使用值集合规则。
对于引用类型有：
NULL 对象类型有：
ROOT 并且codice_406，蕴涵codice_407。就是说codice_4是自反和传递的。但是codice_368并且codice_410，不蕴涵codice_5与codice_6是相同的，因为子类型关系不受形式参数名字、缺省值和包装的影响。
一个类型codice_5可赋值（assignable）给类型codice_6的条件是： 在第一种情况下，没有运行时间错误是有可能的。在第二种情况下，允许赋值一个codice_60到一个codice_422，还允许赋值一个codice_423到一个codice_424，这里分别要求对引用的类型和数组长度的运行时间检查；可以使用类型运算codice_425，将对象类型或有跟踪的引用类型的超类型变量当作其子类型的成员，这时需要运行时间检查，介入它就是为了以安全的方式，将codice_60变量赋值给确知的实际类型codice_422。在第三种情况下，常规的范围检查就能确保特定的codice_5的成员也是codice_6的成员。
一个表达式codice_246可赋值给一个变量codice_51的条件是： 一个表达式codice_246可赋值给类型codice_5，如果codice_246可赋值给类型codice_5的某个变量。如果codice_5不是一个开放数组，这等同声称codice_246可赋值给类型codice_5的任何变量。
介入一个常量、类型、变量、异常或过程的一个名字。这个名字的作用域是包含这个声明的块。一个块可以出现为一个块语句，或一个模块或过程的本体。一个块有如下形式：
Decls BEGIN END
这里的codice_444是一序列的声明，而codice_250是一个语句（经常是顺序复合语句），它是这个块的执行部份。一个块的声明可以介入一个名字最多一次，然而一个名字可以在嵌套的块中重新声明。在块中这些声明的次序，除了确定变量的初始化次序之外无关紧要。
顺序复合语句有如下形式：codice_446，一些编程者使用分号作为语句终结符（terminator），另一些编程者将它用作分隔符（separator）。Modula-3允许这两种风格，语言报告将其用作分隔符。
Modula-3的codice_295语句，无关于Modula-2的同名语句，它有如下形式：，这里的codice_18是一个标识符，codice_246是一个表达式，而codice_250是一个语句（经常是顺序复合语句）。codice_295语句声明了具有作用域codice_250的codice_18，作为变量codice_246的别名，或作为值codice_246的只读名字。表达式codice_246在进入codice_295语句的时候被求值一次。一个单一的codice_295语句可以包含多个绑定，它们顺序的求值，就是说，等价于。
codice_295语句可类比于某种过程调用codice_460，这里的codice_461被声明为：
PROCEDURE P(mode id: typeof e) = BEGIN END P
这里的算符codice_462只是个示意，它不在语言规定之中；如果codice_246是可写的指示符，则codice_464是codice_291，否则codice_464是codice_296。在codice_295语句和调用codice_460之间唯一的区别为，出现在codice_295语句内的自由变量、codice_10和codice_9，是在codice_295语句所在的上下文中解释的，而非在新增加的codice_461的上下文中。
Modula-3语言报告使用codice_295语句定义其他语句，比如，codice_476和codice_477语句分别有如下形式：和，这里的codice_51指示一个序数类型的变量，而codice_80是可选的一个整数取值表达式，如果省略codice_80则缺省为codice_268，这两个语句分别等价于和，这里的codice_5是codice_51的类型，而codice_87代表不出现在codice_80中的变量。
执行一个语句产生一个计算，它可以正常产出结果（在可计算理论中称为停机），发起一个异常，导致一个必查的运行时间错误，或无限循环。如果结果是一个异常，它可以可选的配对上一个实际参数。如果一个表达式作为一个语句的执行部份而求值，这个求值引发一个异常，则这个异常成为这个语句的结果。空语句是无操作的（no-op），在语言报告中写为。
过程调用在这个过程是真正过程的时候是一个语句。调用一个函数过程并丢弃它的结果使用codice_486语句，它有如下形式：codice_487，这里的codice_246是一个表达式。它的效果是求值codice_246并忽略其结果。codice_10语句用于从过程中返回。
赋值语句有如下形式：，这里的codice_51是可写的指示符，而codice_246是可赋值给codice_51所指示变量的表达式。赋值语句将codice_51设置为codice_246的值，codice_51和codice_246的求值次序是未定义的，但codice_246会在codice_51更新之前求值。特别是，如果codice_51和codice_246是有交叠的子数组，以没有元素在被用作来源之前被用作目标的方式进行赋值。
Modula-3提供了选择控制结构codice_502和codice_503语句。codice_502语句有如下形式：
IF B_1 THEN S_1 ELSIF B_2 THEN S_2 ELSIF B_n THEN S_n ELSE S_0 END
这里的这些codice_382是布尔表达式，而这些codice_250是语句。codice_507和每个codice_508都是可选的。codice_502语句依次求值codice_382，直到某个codice_511求值为codice_167，则接着执行codice_513。如果没有表达式求值为codice_167，并且codice_507存在，则执行codice_516。如果没有表达式求值为codice_167，并且codice_507缺席，则codice_502语句是无操作的（no-op）。Modula-3的codice_503语句，不同于Modula-2的同名语句，它有如下形式：
CASE Expr OF  ELSE S_0  END
这里的codice_521是类型为序数类型的一个表达式，而每个codice_522是一个列表，这个列表构成自常量表达式，或用codice_523指示的常量表达式的范围，它表示从codice_524到codice_525含二者的值。如果codice_524超出了codice_525，这个范围为空。如果两个codice_522表示的集合有交叠，或者任何常量表达式不是类型codice_521的一个成员，则是一个静态错误。codice_507是可选的。
codice_503语句求值codice_521。如果结果的值在任何codice_533之中，则执行codice_513。如果这个值不在任何codice_533之中，并且codice_507存在，则执行它。如果这个值不在任何codice_533中，并且codice_507缺席，则发生一个必查的运行时间错误。一些编程者使用竖杠作为初始符（initiator），另一些编程者将它用作分隔符。Modula-3允许这两种风格，语言报告将其用作分隔符。
codice_93语句有如下形式：
TYPECASE Expr OF ELSE S_0 END
这里的codice_521是类型为引用类型的一个表达式，这些codice_250是语句，这些codice_5是引用类型，而这些codice_51是标识符。如果codice_521有类型codice_61，或者任何codice_5不是codice_521的类型的子类型，则为一个静态错误。codice_507和每个codice_549都是可选的。如果codice_550缺席，形式codice_551，是codice_552的简写。
codice_93语句求值codice_521，如果结果的引用值，是任何列出的类型codice_555的成员，则针对其中最小的codice_106，执行codice_513。codice_307是所有引用类型的一个成员，因此codice_67情况只有首先出现才能起作用。如果这个值不是列出的这些类型的一个成员，并且codice_507存在，则执行它。如果这个值不是列出的这些类型的一个成员，并且codice_507缺席，则发生一个必查的运行时间错误。每个codice_550声明类型为codice_555的一个变量，并且它的作用域是codice_513。如果codice_565存在，它在执行codice_513之前被初始化为codice_521的值。
可以使用codice_93语句测试类型为codice_60或对象的一个表达式的值的引用类型，比如写一个过程codice_570，在其中测试codice_203的值是codice_67、codice_573和codice_574中的哪一个类型。
Modula-3提供了循环控制结构codice_297、codice_576、codice_577和codice_578语句，和必须在字面上包围在这四个循环语句中，用于从循环中退出的codice_9语句。语句，循环直到codice_250中有一个发生。语句，被定义为：
LOOP END
语句，被定义为：
LOOP END
codice_297语句有如下形式：，这里的codice_18是一个标识符，而codice_583和codice_584是有相同基础类型的序数表达式，codice_585是整数取值的表达式。而codice_250是一个语句。codice_587是可选的，如果省略，codice_585缺省为codice_268。标识符codice_18指示其作用域是codice_250的一个只读变量，其类型是codice_583和codice_584共同的基础类型。codice_297语句的语义，可如下这样用codice_577和codice_295语句精确的定义为一个块：
VAR BEGIN END
这里的codice_5是codice_18的类型，codice_106、codice_600和codice_601代表不出现在codice_297语句中的变量。从codice_297语句的这个定义可以看出，如果一个codice_297循环的上界是codice_605或codice_606，就应当将它改写为codice_577循环来避免溢出。
异常声明有如下形式：codice_608，这里的codice_18是一个标识符，而codice_5是除了开放数组之外的一个类型，它声明了codice_18是具有实际参数类型codice_5的异常。如果省略了codice_613，这个异常不接受实际参数。异常声明只允许出现在接口和模块的最外层作用域之中。所有的声明的异常都是各不相同的。
codice_614语句有两种形式，没有实际参数的形式：，这里的codice_246是不接受实际参数的一个异常，它的结果是发起异常codice_246；具有实际参数的形式：，这里的codice_246是接受实际参数的一个异常，而codice_87是可赋值给codice_246的实际参数类型的一个表达式，它的结果是引发具有配对实际参数codice_87的异常codice_246。
Modula-3的异常处理，基于了codice_294语句。采用类似的块系统的有Delphi、Python、Scala和Visual Basic.NET。 codice_294语句有如下形式：
TRY EXCEPT  ELSE Handler_0  END
这里的codice_624和每个codice_625都是语句，每个codice_18指名一个异常，而每个codice_565是一个标识符。codice_628和每个codice_550都是可选的。每个codice_550声明一个变量，其类型是异常codice_631的实际参数类型，而它的作用域是codice_632。如果codice_550缺席，形式codice_634，是codice_635的简写。
codice_636子句执行codice_624。如果结果是正常的，则忽略codice_638等子句。如果codice_624引发任何列出的异常codice_631，则执行codice_632。在处理具有配对实际参数codice_87的异常codice_631的时候，codice_565在执行codice_632之前被初始化为codice_87。如果codice_624引发任何其他异常，并且codice_628存在，则执行它。在这两种情况的任何之一下，codice_294语句的结果是选出的处理器的结果。如果codice_624引发未列出的异常，而codice_628缺席，则codice_294语句的结果是codice_624引发的异常。
Modula-3还提供codice_654语句，它有如下形式：，它执行语句codice_655接着执行语句codice_656。如果codice_655的结果是正常的，则codice_636语句的结果等价于codice_446。如果codice_655的结果是异常，并且codice_656的结果是正常，则在codice_656执行之后，重新发起来自codice_655的异常。如果二者的结果都是异常，则codice_636语句的结果是来自codice_656的异常。
在Modula-3中，和语句的语义，分别被定义为发起叫做codice_11和codice_12的异常。codice_11不接受实际参数，codice_12接受任意类型的实际参数，程序不能显式的命名这些异常。语句，非正式的等价于：
TRY EXCEPT  END 一个过程要么是codice_59，要么是有如下构成的三元组： 形式参数有如下形式：，这里的： 形式，是的简写。
codice_291形式参数绑定到对应的实际参数所指示的变量上，也就是说它是别名。对于codice_291形式参数，实际参数必须是可写的指示符，它的类型同于形式参数的类型，或者在codice_291数组形式参数的情况下，它可赋值给这个形式参数。
codice_292形式参数绑定到具有未用的位置的一个变量上，并且它被初始化为实际参数对应的值。对于codice_292或codice_296形式参数，实际参数是可赋值给形式参数类型的任何表达式，并且放开了针对赋值局部过程的禁止。
codice_296形式参数，如果实际参数是指示符并且有与形式参数相同的类型，或者是可赋值给形式参数的类型的一个数组类型，则被当作codice_291形式参数对待，它的只读语义体现在指定这个指示符为只读的，否则被当作codice_292形式参数对待。
在签名中，如果省略了codice_703，则这个过程是真正（proper）过程，否则为函数过程；如果省略了codice_704，则假定它为codice_705。一个过程发起未包括在codice_386集合中的一个异常，是一个必查的运行时间错误，如果语言实现将这个运行时间错误映射成一个异常，则这个异常隐含的包括在所有的codice_386子句中。
有两种形式的过程声明：只允许出现在接口中的，和只允许出现在模块中的，这里的codice_18是一个标识符，codice_709是过程签名，而codice_382是一个块。在一个模块的最外层作用域内声明的过程是顶层过程，其他过程是局部过程。局部过程可以作为形式参数传递但不能被赋值，因为在栈实现下，局部过程在包含它的栈桢被弹出后会成为无效的。
过程类型声明有如下形式：，这里的codice_709是签名规定。一个过程codice_461是过程类型codice_5的一个成员，或称为是它的一个值的条件为，它是codice_307，或者它的签名被codice_5的签名所含盖（cover）。这里的签名codice_716含盖签名codice_717的条件是： 过程常量是声明为过程的一个标识符。过程变量是声明为具有过程类型的一个变量。例如：
PROCEDURE P(txt: TEXT := "P") =  BEGIN END P; VAR q: PROCEDURE(txt: TEXT := "Q") := P;
声明了过程常量codice_461和过程变量codice_723。两个过程如果有一致的闭包，就是说它们涉及相同的过程体和环境，则二者相等即有相同的值。形式参数名字和缺省值，影响一个过程的类型即签名，而非这个过程的值。将一个过程常量赋值给一个过程变量，改变这个它的值，而非它的类型。比如上例中有：codice_724为codice_167。缺省的形式参数的解释，由一个过程的类型来确定，而非这个过程的值。比如上例子中：codice_726打印codice_461，而codice_728打印codice_729。
过程调用有如下形式：codice_730，这里的codice_461是一个过程取值的表达式，而codice_274是关键字或位置绑定的一个列表。关键字绑定有如下形式：codice_733，这里的codice_734是一个表达式，而codice_735是一个标识符。位置绑定有如下形式：codice_734，这里的codice_734是一个表达式。当关键字和位置绑定混合在一个调用中的时候，位置绑定必须前导于关键字绑定。如果绑定列表为空，圆括号仍然是需要的。
绑定列表要如下这样重写，来适合codice_461的类型签名：首先，每个位置绑定codice_734，若为codice_274中的第codice_106个绑定，则通过补充上第codice_106个形式参数的名字，转换成关键字绑定增加到关键字绑定列表中。其次，对于有缺省值并且在第一步之后没有被绑定的每个形式参数，将它的形式参数的名字codice_735和它的缺省值codice_72，形成关键字绑定codice_745增加到关键字绑定列表。重写成的关键字绑定列表必须只绑定形式参数，并且必须只绑定每个形式参数正好一次。
执行过程调用，需要求值过程取值表达式codice_461和它的实际参数，绑定形式参数，并执行过程体。codice_461和它的实际参数的求值次序是未定义的。调用一个未定义或codice_307过程，是一个必查的运行时间错误。调用具有过程体codice_382的真正过程，在绑定了实际参数之后等价于：
TRY EXCEPT END 而调用具有过程体codice_382的函数过程等价于：
TRY EXCEPT END 对于常量、类型或过程声明codice_751、变量声明codice_752、异常声明codice_753或揭示codice_751，如果codice_755出现在codice_20的任何部份展开之中，则它是递归的。对于省略了类型的变量声明codice_757，如果codice_755出现在codice_342的类型codice_20的任何部份展开中，则它是递归的。允许这种声明的条件，是codice_755在codice_20的任何部份展开中所有的出现为如下三者之一：在类型构造子codice_183或codice_764的某个出现之内，在类型构造子codice_765的一个字段或方法类型之内，或者在一个过程体之内。下面是合法的递归声明的例子：
TYPE  EXCEPTION E(PROCEDURE() RAISES {E}); PROCEDURE P(b: BOOLEAN) = BEGIN END P; Modula-3的设计者认为：ALGOL家族的趋势，在1960年代是朝向控制流程和数据结构特征，在1970年代是朝向特征如接口、不透明类型和泛型，在1980年代是采纳来自LISP家族和始自BCPL的C家族的仔细挑选的技术。人们越是更好的理解程序，就越是使用更大的建造块去构造它。指令之后是语句，语句之后是过程，过程之后是接口，下一步应当是抽象类型。在理论层面，抽象类型，是通过其操作的规定，而非通过其数据的表示，来定义的类型。
Modula-2的最成功特征，是提供了在模块之间的显式接口，故而接口在Modula-3中保留而在本质上没有变化。到模块的接口，是披露了模块公开部份的声明搜集，而未声明于接口中的模块中的东西是私有的。模块导入它所依赖的接口，而导出它所实现的接口（在Modula-3中可以是多个接口）。
在现代编程语言的实现下，一个抽象类型的值，被表示一个对象，它的操作由叫做对象的方法的过程值的一个套件来实现。一个新的对象类型，可以定义为现存类型的子类型，在这种情况下新类型拥有旧类型的所有方法，并且可能还有新的方法（继承）。新类型可以为旧方法提供新的实现（）。对象类型和Modula-2的的组合，产生了一个新事物：部份不透明（partially opaque）类型，这里的一个对象的一些字段在一个作用域内是可见的，而其他的是隐藏的。
泛型模块是一种模板，在其中一些导入的接口被当作形式参数，它们在泛型的时候要绑定到实际接口。不同的泛型实例是独立编译的，源代码程序被重复使用，而编译后的代码对不同实例通常是不同的。为保持简单性，在Modula-3中泛型被限制在模块层面，泛型的过程和类型不孤立存在，并且泛型形式参数必须都是完全的接口。
将计算分解入并发进程（或线程）中是关注点分离的基本方法。Modula-2提供的线程很弱，本质上相当于协程。Modula-3采用了霍尔的监视器，它是并发编程的更坚实基础。在设计中加入了简化的Mesa同步原语，它足够成功而在实质上没有改变的结合入了Modula-3。
一个语言特征是不安全的，如果它的滥用可以破坏运行时系统，使得程序的进一步运行不忠实于语言的语义，不安全特征的一个例子，是没有边界检查的数组赋值。一个安全的程序的一个错误，可以导致计算中止，并给出运行时间错误信息或给出错误解答，但它不会导致计算分崩离析。Modula-3在这个领域里跟从Cedar，接受只在显式的标记为不安全的模块中才允许的少量不安全特征。
接口中的声明，除了任何变量初始化必须是常量，和过程声明必须只能指定签名而不能有过程体之外，同于在块中的声明。接口有如下形式：
INTERFACE id; END id. 这里的codice_18是命名这个接口的标识符，codice_767是一序列的导入语句，而codice_444是一序列的声明。在codice_444中的名字和可见的导入的名字必须是各不相同的。两个或更多个接口形成导入环是静态错误。典型的接口定义，通常为每个接口定义一个数据结构（记录或对象）以及任何的支持过程。
模块除了实体名字的可见性之外，就像是一个块。一个实体在一个块中是可见的，如果它被声明在这个块中，或在某个包围的块中；而一个实体在一个模块中是可见的，如果它被声明在这个模块中，或在这个模块所导入或导出的一个接口中。模块有如下形式：
MODULE id EXPORTS Interfaces; Block id.
这里的codice_18是命名这个模块的一个标识符，codice_771是这个模块导出的那些接口的不同名字的一个列表，codice_767是一序列的导入语句，而codice_773是一个块，它是模块体。名字codice_18必须重复于终结模块体的codice_775之后。codice_776可以省略，在这种情况下codice_771缺省为codice_18，即模块将缺省导出相同名称的接口。Modula-3中的导出codice_2，与Modula-2中的导出codice_780无关，它在概念上对应于Modula-2的“实现”。
如果模块codice_781导出了接口codice_342，则在codice_342中声明的所有名字在codice_781中是不加以限定而可见的。一个模块codice_781导出一个接口codice_342，可以重新声明在这个接口中声明的一个或多个过程，为其提供过程体。在codice_781中的签名，必须被在codice_342中的签名所含盖。要确定在对这个过程的调用中的关键字绑定的解释，在codice_781内使用codice_781中的签名，在其他地方使用codice_342中的签名。除了重新声明导出的过程之外，在codice_773的顶层中声明的名字，可见的导入的名字，和在导出的接口中声明的名字必须是各不相同的。
一个程序的模块和接口的名字叫做全局名字。查找全局名字的方法是依赖于实现的，比如通过文件系统查找路径。一个模块或接口codice_793导入一个接口codice_342，从而使得在codice_342中声明的实体和揭示在codice_793中可见，但不包括codice_342所导入的那些。一个模块codice_781使用了接口codice_342，如果codice_781导入或导出了codice_342，或者codice_781使用了导入codice_342的一个接口。Modula-3中所有的编译单元，要么是接口要么是模块。任何编译单元都可以使用codice_804语句从其他接口导入标识符。与其他语言的包含功能不同，任何标识符都可以追踪到它的起源位置。
codice_804语句有如下的典型使用形式：，它导入全局名字为codice_342的接口，并给它一个同样的局部名字，从而使用点表示法访问接口中的实体（类似于访问记录中的字段）。比如接口中的主要类型按惯例命名为codice_5，则使用它时采用的限定形式为codice_808。如果导入接口的名字与模块内的其他实体的名字发生冲突，则可以使用这样的形式给与它不同的局部名字。
codice_804语句还有如下的另一种形式：，它为在接口codice_342中声明为codice_755的实体，介入一个局部名字codice_755，比如：，并且不加限定的使用它，比如：。局部绑定优先于全局绑定，例如：，为全局名字为codice_813的实体介入了局部名字codice_755。非法使用相同的局部名字两次是静态错误。
一个程序是模块和接口的搜集，包含了任何它的模块或接口所导入或导出的所有接口，并且在其中没有重复定义的过程、模块或接口。执行一个程序的效果是执行它的所有模块的模块体。模块的执行次序受到初始化规则的约束：如果模块codice_781依赖于模块codice_755并且codice_755不依赖于codice_781，则codice_755的模块体将先于codice_781的模块体执行。这里的模块codice_781依赖于模块codice_755，如果M使用了codice_755导出的一个接口，或者codice_781所依赖的一个模块依赖于codice_755。
其模块体最后执行的模块叫做主模块。在初始化规则不能唯一的确定它的情况下，语言实现提供了指定这个主模块的方法，即主模块是导出codice_1的模块，它的内容是依赖于实现的。程序执行在主模块终止的时候终止，即使并发的控制线程仍在执行。
下面是接口与模块的一个规范性的例子，是有隐藏表示的一个公开堆栈：
INTERFACE Stack; END Stack.
MODULE Stack;
BEGIN END Stack.
如果多于一个模块需要此堆栈的表示，则应当把它转移到私有接口中，从而在需要它的任何地方的都可以导入它：
INTERFACE Stack; END Stack.
INTERFACE StackRep; END StackRep.
MODULE Stack; BEGIN END Stack. 一个对象要么是codice_59，要么是到有配对的方法套件的一个数据记录的引用，方法套件是接受这个对象作为第一个实际参数的那些过程的一个记录。这个数据记录可以包含经由对象类型的子类型介入的增加字段，这个套件可以包含经由子类型介入的增加方法。对象赋值是引用赋值。要复制一个对象的数据记录到另一个对象，这些字段必须单独的赋值。
Modula-3意图保持采用对象这个最简单的术语，而非在其他面向对象语言中对应的术语类。对象类型声明采用如下形式：
TYPE T = ST OBJECT
这里的codice_828是可选的超类型，如果省略则缺省为codice_73，codice_830是完全如同记录类型那样的字段声明的一个列表，codice_831是方法声明的一个列表，而codice_832是方法覆盖的一个列表。在字段和方法声明中介入的名字，必须相互不同，并且不同于在覆盖声明中的名字。codice_5的字段构成自codice_828的字段和随后的新声明的字段。codice_5的方法构成自经过codice_836中的覆盖修改的codice_828的方法，和随后的codice_838中声明的方法。codice_5有着同codice_828一样的引用类。
关键字codice_765可选的可以前导上codice_186或codice_184来给对象加铭牌，使之唯一而避免结构等价，这里的codice_165是文本常量。其含义同于非对象的引用类型，codice_165被省略时，系统自动生成唯一性的一个字符串。
方法声明有如下形式：codice_846，这里的codice_348是个标识符，codice_709是过程签名，而codice_849是顶层过程常量。方法声明指定了codice_5的方法codice_348有签名codice_709和值codice_849。如果省略了codice_854假定它为codice_855。如果codice_849非空，它的第一个形式参数必须是缺省的模态codice_292，并有着codice_5的某个超类型的类型（包括且经常是codice_5自身），并且去除了第一个形式参数结果就是codice_709所含盖的签名。
方法（override）有如下形式：codice_861，这里的codice_348是超类型codice_828的方法的名字，而codice_849是顶层过程常量。方法覆盖指定了codice_5的方法codice_348是codice_849，并非指定codice_868。如果codice_849非空，它的第一个形式参数必须是缺省的模态codice_292，并有着codice_5的某个超类型的类型（包括且经常是codice_5自身），去除了codice_849第一个形式参数结果就是codice_828的codice_348方法所含盖的签名。举例说明：
TYPE  PROCEDURE ProcSuper(self: Super) = ... ;  PROCEDURE ProcSub(self: Sub) = ... ;
这里的过程codice_876和codice_877是类型codice_878和codice_879的对象的codice_880方法的候选值。例如：
如果codice_5是对象类型或到记录的引用，codice_196操作有如下形式：，这里的codice_274是用来初始化新字段的关键字绑定的一个列表，不允许位置绑定。每个绑定codice_884将字段codice_331初始化为值codice_51。如果codice_5是对象类型，则codice_274还可以包括形如codice_889的方法覆盖，这里的codice_348是codice_5的一个方法而codice_461是一个顶层过程常量。是的语法糖。
如果codice_338是一个对象，则codice_324指示在codice_338的数据记录中名为codice_331的数据字段。codice_324是可写的指示符，它的类型是这个字段的所声明的类型。如果codice_348是codice_338方法之一，以codice_900形式的过程调用，指示执行codice_338的codice_348方法，这等价于：codice_903。
如果codice_5是对象类型而codice_348是codice_5的方法的名字之一，则codice_327指示codice_5的codice_348方法。它的过程类型的第一个实际参数有类型codice_5，而第一个实际参数对应的形式参数名字是未指定的，因此在调用codice_327时，第一个实际参数必须按位置来指定，不能用关键字。这种表示法便于子类型方法调用它的某个超类型的对应方法。
在子类型中的字段或方法遮盖（mask）了在超类型中的任何同名的字段或方法。要访问被遮盖的字段，使用类型运算codice_912来将子类型变量当作超类型的成员，这里的codice_5必须是对象类型或有跟踪的引用类型，而codice_87必须可赋值给codice_5。codice_425在检查了codice_87是codice_5一个成员之后返回codice_87，如果检查失败则发生运行时间错误。
下面的例子展示了在声明新方法和覆盖现存方法之间的不同，首先声明如下：
TYPE VAR
然后可以用codice_920激活codice_921，用codice_922激活codice_923，用codice_924激活codice_925，如此调用在覆盖和扩展之间没有区别。但是扩展的codice_926的方法套件有两个方法，而覆盖的codice_165的方法套件只有一个方法，这可以通过使用codice_912将子类型的变量codice_165和codice_926视为超类型codice_878的成员来披露：codice_932激活codice_923，codice_934激活codice_935。
对象不能，因为在语言实现中，一个对象变量的静态类型不确定它的数据记录的类型。对象类型确定了关乎数据记录字段和方法套件的超类型链的前缀的那些类型。
下面是语言设计者提出的对象的一种可能实现的梗概，一个对象可以表示为它的数据记录的第一个字的地址。前面的字存储一个对象头部，它包含一个唯一于对象类型的类型代码。这些类型代码是小型整数，对每个对象类型和每个有跟踪的引用类型都有一个代码。在对象头部之前的字，存储到这个对象的方法套件的一个引用。如果这个对象没有方法，这个字可以省略。这还允许对象共享方法套件，这是常见情况。如果codice_338是一个对象，codice_937是它的数据字段之一，而codice_348是它的方法之一，则在这种表示下：
这里假定了字段和方法以自然方式表示为偏移量。进一步的问题是如何高效的测试一个对象codice_338是否有着类型codice_5，这是codice_280和codice_93语句所需要的。codice_280的最简单实现，是维护一个以类型代码为索引的数组codice_944，codice_945是其类型代码为codice_946的对象类型的超类型的类型代码，如果它没有超类型则为codice_307。要测试codice_338是否是一个codice_5，使用一个循环来计算codice_5的类型代码是否出现在如下序列之中：
TYPECODE(o), st[TYPECODE(o)], st[st[TYPECODE(o)]], ... NIL
这个序列可以称为codice_338的类型的超类型路径，而它的长度可称为codice_338的类型的深度。利用上每个类型的深度都是编译时间确定的，因此可以同相应的类型代码一起存储的事实，可以有更快速的codice_280实现。如果codice_5的类型代码，出现在类型codice_6的超类型路径上，它就该在位置codice_956上。如果每个类型的超类型路径都是顺序数组，这意味着codice_280可以用恒定时间实现。因为超类型路径通常不太长，这是一个有吸引力的策略。在不常见的对象类型有非常长的超类型链的情况下，只有这个链的直到某个极大长度的一个前缀，会被顺序的存储。在运行时间，这个深度差如果超出这个链的顺序存储的长度，实现必须回退到链表。
（opaque）类型声明有如下形式：，这里的codice_5是标识符，而codice_6是指示一个引用类型的表达式。它将名字codice_5介入为不透明类型，并披露了codice_6是codice_5的超类型。
Modula-3的揭示（revelation）机制，将关于一个不透明类型的信息，介入到一个作用域之内，不同于其他声明，揭示不介入新的名字。不同的作用域，可以披露（reveal）关于一个不透明类型的不同的信息。例如，某个不透明类型，在一个作用域内知晓为codice_60的子类型，在其他的作用域内可以知晓为codice_73的子类型。
不透明类型名字所指示的实际类型叫做具体类型。codice_5的具体类型，必须披露于程序的其他地方。在对象声明中，如果codice_828被声明为不透明类型，则只在知晓codice_828的具体类型为对象类型的作用域内，codice_5的声明是合法的。如果codice_5被声明为不透明类型，则只在完全知晓codice_5的具体类型，或者知晓它为对象类型的作用域内，codice_196是合法的。
揭示分为两种：部份的和完全的，一个程序可以包含一个不透明类型的任意多个部份揭示，但必须包含唯一的一个完全揭示。
部份揭示有如下形式：，这里的codice_124是类型表达式（可能就是个名字），而codice_5是被声明为不透明类型的一个标识符（可能有限定）。它披露了codice_124是codice_5的超类型。在任何作用域内，对一个不透明类型披露的超类型，必须是在子类型关系下是线性有序的。就是说，如果披露了codice_976和codice_977，则必须也要披露要么codice_978要么codice_979。是合法的非递归声明。
完全揭示有如下形式：，这里的codice_124是类型表达式（不能就是个名字），它的最外层类型构造子，是有铭牌的一个引用或对象类型，而codice_5是被声明为不透明类型的一个标识符（可能有限定）。这个揭示指定了codice_124是codice_5的具体类型。在任何作用域内，披露为codice_5的超类型的任何类型，都必须是codice_124的超类型，否则是一个静态错误。不同的不透明类型有不同的具体类型，因为codice_124包含了一个铭牌并且在程序中所有的铭牌都是独一的。是非法的递归声明。
揭示只允许用在接口和模块的最外层作用域内。在接口中的揭示可以被导入到任何需要它的作用域之内。揭示提供了向客户隐藏实现细节的，在概念上简单清晰却非常强力的机制，例如：
INTERFACE I;  END I.
INTERFACE IRep; END IRep.
INTERFACE IClass; END IClass.
导入codice_342的编译单元见到的codice_808是codice_73的不透明子类型，因而被限制为可以分配类型codice_808的对象，把它们传递给codice_991，或声明codice_808的子类型。导入codice_993的编译单元见到的codice_808是具体类型，它是有扩展的codice_995字段的codice_996的子类型。导入codice_997的编译单元见到的codice_808是codice_996的不透明子类型，因而可以锁定类型codice_808的对象。
在泛型接口或模块中，某些导入的接口名字被当作形式参数，它们在泛型被实例化的时候要绑定到实际接口上。泛型接口及其实例有如下左侧的形式，并等价于右侧定义的普通接口：
这里的codice_1001是命名这个泛型接口的一个标识符，codice_1002是叫做codice_1001的形式导入的标识符的一个列表，而codice_624同在非泛型接口中一样，是一序列导入和随后的一序列声明。这里的codice_342是这个实例的名字，而codice_1006是codice_1001的形式导入要绑定的实际接口的一个列表。
泛型模块及其实例有如下左侧的形式，并等价于右侧定义的普通模块：
这里的codice_1001是命名这个泛型模块的一个标识符，codice_1002是叫做codice_1001的形式导入的标识符的一个列表，而codice_624同在非泛型模块中一样，是一序列的导入和随后的一个块。这里的codice_342是这个实例的名字，codice_20是由codice_781导出的接口的一个列表，而codice_1006是codice_1001的形式导入要绑定的实际接口的一个列表。codice_1017可以省略，在这种情况下它缺省为codice_1018。泛型模块自身没有导出，它们只在被实例化时提供。
泛型接口及其对应的泛型模块（与C++模板一样）可以轻松定义和使用抽象数据类型，但粒度在模块级别，裸露的类型codice_44或codice_1020不能使用，相比之下，它们在C++模板中可以使用。例如，可以定义泛型堆栈：
GENERIC INTERFACE Stack(Elem); END Stack. GENERIC MODULE Stack(Elem);
BEGIN END Stack. 然后使用接口例如codice_1021，对其进行实例化，只要这个接口定义了泛型模块所需的属性即可： INTERFACE IntegerElem; END IntegerElem.
INTERFACE IntStack = Stack(IntegerElem) END IntStack. MODULE IntStack = Stack(IntegerElem) END IntStack. Modula-3下的面向对象编程，经常采用部份不透明类型，它通过如下惯用法来声明：，这里的不透明类型codice_5，支持在随后定义的对象类型中的字段和方法，而不会披露codice_5的确切结构，也不披露codice_5可能支持的其他方法。
下面的例子，定义一个接口codice_1025，具有按习惯约定命名的两个类型，导出类型codice_5，和公开对象类型codice_1027，这里声明了codice_5是codice_1027的不透明子类型，codice_1027具有两个方法codice_1031和codice_1032；随后是codice_1025接口的完全实现：
INTERFACE Person; END Person. MODULE Person;
BEGIN END Person. 要建立一个新的codice_1034对象，要使用内建操作codice_191，并调用方法codice_1032：
VAR jim := NEW(Person.T).init("Jim", 25); 下面是整数堆栈的例子：
INTERFACE IntegerStack; END IntegerStack. MODULE IntegerStack;
BEGIN END IntegerStack.
创建新堆栈在这里的部份不透明类型实现下为：，在上述的不透明类型实现下为：。而压入一个数在这里的部份不透明类型实现下为：，在上述的不透明类型实现下为：。
语言支持多线程和在线程间的同步。在运行时库（m3core）中有一个必要接口叫做codice_78，它支持采用分叉会合模型的多线程应用。这里还预定义不透明类型codice_1038被用来同步多个线程，并保护共享数据免于具有可能损害或竞争条件的同时访问。codice_996是一个对象，因此可以从它派生其他对象。
codice_1040语句有如下形式：，这里的codice_250是一个语句，而codice_1042是一个表达式，它等价于：
WITH m = mu DO END
这里的codice_348表示不出现在codice_250中的一个变量。codice_1040语句介入一个互斥锁要锁定的块，并暗含着在代码执行轨迹离开这个块时的解锁它。
某些功能被认为是不安全的，编译器无法再保证结果是一致性的（例如，当与C编程语言交接时）。在codice_1046或codice_1047前面加上前缀关键字codice_1048，可用于告诉编译器启用语言的某些不安全的低级功能。例如，在codice_1048模块中，使用codice_283将整数的诸位元复制成浮点codice_1020数，使用codice_1052释放无跟踪的内存。
一个接口是内在安全的，如果在安全模块中使用这个接口，无法产生不核查的运行时间错误。如果导出一个安全接口的所有的模块都是安全的，编译器保证这个接口的内在安全性。如果导出一个安全接口的任何模块是不安全的，就要编程者而非编译器，去做这种保证了。安全接口导入不安全接口，或安全模块导入或导出不安全接口，都是静态错误。导入不安全接口的编译单元本身必定也是不安全的。
尽管Modula-3没有获得主流地位，DEC-SRC M3发行的某些部份做到了。可能最有影响的一部份是网络对象库，它形成了Java包括了网络协议的最初的远程方法调用（RMI）实现的基础。在Sun从通用对象请求代理架构（CORBA）标准转移到基于IIOP的协议的时候才被放弃。Java关于远程对象的垃圾收集的文档仍提及了Modula-3网络对象为其先驱性工作 。
Python从Modula-3借鉴了模块系统、异常系统和关键字参数，Python的类机制受到C++和Modula-3的启发。Nim利用了Modula-3的某些方面比如有跟踪和无跟踪的指针。