Modula3 是一種系統程式語言，它是叫做的升級版本的 Modula2 的後繼者。雖然它已經在研究界有了影響力，受其影響的語言有 Java、C 和 Python，但未能在工業上被廣泛採用。它是在 1980 年代末由在數字裝置公司（DEC）（SRC）和 Olivetti 研究中心（ORC）的、James Donahue、Lucille Glassman、Mick Jordan（之前在 Olivetti 軟體技術實驗室工作）、Bill Kalsow 和設計。 Modula3 的主要特點，是保持系統程式語言的強力，同時具有簡單性和安全性。Modula3 意圖延續 Pascal 的型別安全和 Modula2 的模組化程式設計傳統，同時為實際程式設計引入新構造。特別是 Modula3 添加了如下支援：例外處理、關鍵字引數與預設引數值、有跟蹤的引用與垃圾回收、面向物件、不透明型別及其披露、泛型、多執行緒和不安全程式碼顯式標記。Modula3 的設計目標，是以非常基本的形式，實現指令式程式語言的大部份重要的現代特徵。因此省略了涉嫌危險和複雜的特徵，如多重繼承和運算子過載。 發展歷史 Modula3 專案始於 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 編譯器的語言。正如修訂的 Modula3 報告所述 Modula3 report revised Luca Cardelli James Donahue Lucille Glassman Mick Jordan Bill Kalsow Greg Nelson DEC Systems Research Center SRC Research Report 52 November 1989，該語言演化自 Mesa、Modula2、Cedar 和，還受到其他語言的影響如：Object Pascal，Oberon 和。 在 20 世紀 90 年代，Modula3 作為一種教學語言獲得了可觀的傳播，華盛頓大學在 1994 年發行的微核心作業系統是用 Modula3 開發的，但它從未廣泛用於工業用途。造成這種情況的原因，可能是 Modula3 的關鍵支持者 DEC 的消亡，特別是在 1998 年 DEC 被出售給康柏之前就不再有效地維護它了。無論如何，儘管 Modula3 有著簡單性和強大功能，似乎當時對有限實現了面向物件程式設計的過程式編譯語言的需求很少。 Critical Mass 公司曾在一段時間內提供了一個名為 CM3 的商業編譯器，它由以前 DEC SRC 的在 DEC 被出售給 Compaq 之前僱用的一個主要實現者維護，和叫做 Reactor 的一個整合開發環境以及可擴充套件的 Java 虛擬機器（以二進位制和源格式許可發行並可用 Reactor 來構建）。但該公司在 2000 年停止了活動，並將其產品的一些原始碼提供給了 elego 軟體解決方案有限公司。 基本上，Modula3 的唯一企業支持者是 elego 軟體解決方案有限公司，它繼承了 Critical Mass 的資源，並且已經以原始碼和二進位制形式釋出了幾個版本的 CM3 系統。Reactor IDE 在幾年後才開源釋出，新的名稱是 CM3IDE。2002 年 3 月，elego 還接管了此前由蒙特利爾工程學院維護的另一個活躍的 Modula3 發行版 PM3 的儲存庫，在此後幾年間以 HM3 名義進行了持續改進，直至最終被淘汰。 Modula3 是文件記錄了語言特徵演化的少見語言之一，在《用 Modula3 系統程式設計》中 Systems Programming with Modula3，收錄了設計者對四個設計要點的討論：結構等價與名稱等價、子型別規則、泛型模組和引數模態。Modula3 現在主要是在大學中的比較程式語言課程中教授，其教科書已絕版。 程式示例 Modula3 中所有的程式至少具有一個模組檔案，而大多數程式還包括一個介面檔案，客戶端使用它來訪問來自模組的資料。語言語法的一個常見示例是 Hello world 程式： MODULE Main IMPORT IO BEGIN IOPut Hello Worldn END Main 與其他語言一樣，Modula3 程式必須有匯出 Main 介面的實現模組，如上述示例中實現模組預設匯出了同名的介面，它可以處在名為 Mainm3 的檔案中；或者是透過 EXPORTS 匯出 Main 介面的實現模組，比如： MODULE HelloWorld EXPORTS Main IMPORT IO BEGIN IOPut Hello Worldn END HelloWorld 建議這個模組所在的檔案的名字與實際模組名字相同，當它們不同時編譯器只是發出一個警告。 語言設計理念 Modula3 委員會將 Modula3 設計為 ALGOL 語言家族的現代代表，他們認為： 始自 BCPL 的 C 語言家族，其優美在於以適度的代價得到了相對組合語言的巨大飛躍，但它們接近於目標機器的低層是天然有危險性的；其中的衍生語言 C，透過增加物件豐富了 C，但它放棄了 C 的最佳優點簡單性，卻沒有消除它最差缺點即低層程式設計模型。 另一個極端是 LISP 語言家族，它們有著混合了 lambda 演算和配對函數理論的，但它們趨於難以高效實現，因為在程式設計模型中值的統一對待，招致了所有的值都由指標統一表示的執行時間系統；這個家族的語言的良好實現避免了多數代價而能用於系統程式設計，但它們普遍秉性仍舊嚮往堆分配而非棧分配，這種執行時間系統經常將它們孤立於封閉環境中，而不能容納用其他語言寫的程式。 ALGOL 語言家族處在這兩個極端之間，它的現代代表包括 Pascal、Ada、Modula2 等，這些語言擁有的程式設計模型反映了隨機存取機在工程上的約束，隱藏了任何特定於機器的細節。它們放棄了 LISP 家族的優美和數學對稱性，使得無須特殊技巧就可能高效的實現，並且避免了 C 家族的多數危險和依賴機器的特徵。 ALGOL 家族語言都有強型別系統，其基本想法是把值空間劃分成型別，限制變數持有單一型別的值，並且限制運算應用於固定型別的運算數。這個語言家族的趨勢，在 1960 年代是朝向控制流程和資料結構特徵，在 1970 年代是朝向特徵如介面、不透明型別和泛型，在 1980 年代是採納來自 LISP 家族和始自 BCPL 的 C 家族的仔細挑選的技術。 Modula3 委員會堅持一個自稱為 複雜度預算 的設計原則：在五十頁內將語言準確而易讀的描述出來，為此只容納最有用的特徵。精選出來的特徵直接針對兩個主要目標： 介面、物件、泛型和執行緒，提供有助於建造大型程式的基礎抽象模式； 不安全程式碼的顯式標記、自動垃圾收集和例外，有助於讓程式更加安全和健壯。 這些特徵中任何一個都沒有特殊的新穎性，但是組合起來是簡單而強力的。人們越是更好的理解程式，就越是使用更大的建造塊去構造它。指令之後是語句，語句之後是過程，過程之後是介面，下一步應當是抽象型別。在理論層面，抽象型別，是透過其操作的規定，而非透過其資料的表示，來定義的型別。 詞法記號 關鍵字： AND ANY ARRAY AS BEGIN BITS BRANDED BY CASE CONST DIV DO ELSE ELSIF END EVAL EXCEPT EXCEPTION EXIT EXPORTS FINALLY FOR FROM GENERIC IF IMPORT IN INTERFACE LOCK LOOP METHODS MOD MODULE NOT OBJECT OF OR OVERRIDES PROCEDURE RAISE RAISES READONLY RECORD REF REPEAT RETURN REVEAL ROOT SET THEN TO TRY TYPE TYPECASE UNSAFE UNTIL UNTRACED VALUE VAR WHILE WITH 保留識別符號： ABS ADDRESS ADR ADRSIZE BITSIZE BOOLEAN BYTESIZE CARDINAL CEILING CHAR DEC DISPOSE EXTENDED FALSE FIRST FLOAT FLOOR INC INTEGER ISTYPE LAST LONGINT LONGREAL LOOPHOLE MAX MIN MUTEX NARROW NEW NIL NULL NUMBER ORD REAL REFANY ROUND SUBARRAY TEXT TRUE TRUNC TYPECODE VAL 運算子： 此外，註釋是開於 併合於 的任意字元的序列。註釋可以巢狀並可以擴充套件跨越多於一行。 基礎性語法和語義 Modula3 承襲了 ALGOL 家族傳統的強型別，並且為了使型別系統儘可能的統一，採用瞭如下原則： 首先，型別或目標型別確定是沒有歧義的，所有的表示式的型別由它的子表示式來確定，而非由它的使用來確定。 其次，沒有自動轉換。 第三，可賦值性和型別相容性，是依據單一的在語法上用算符 指定的子型別關係來定義的，它具有如下性質：如果 T 是 U 的子型別，則所有的 T 的成員都是 U 的成員，子型別關係是自反和傳遞的；子型別關係是處理具有繼承的物件所需要的，但也能用於確定常規型別的相容性規則。 一個典型的不安全執行時間錯誤，是釋放仍可由活躍引用（懸空指標）觸及的資料結構。避免這個問題的唯一可靠方式，是不再觸及儲存的自動釋放，或稱為垃圾收集。Modula3 因而提供了有跟蹤的引用，它類似於 Modula2 的指標，除了它們所指向的儲存被儲存在有跟蹤的堆之中之外，在這裡它們將在到它們的引用都消失時自動釋放。垃圾收集的另一個巨大利益是簡化了介面，沒有垃圾收集，介面就必須規定客戶或實現是否有責任釋放每個分配的引用，和在什麼條件下可以安全的去這麼做。 例外是一次退出多層作用域的控制結構。一個例外被重複的發起退出當前活躍的作用域，直到找到給這個例外的處理器（handler），並將控制權移交給這個處理器，如果沒有處理器，則計算以某種依賴於系統的方式終止，比如進入偵錯程式。在 Modula3 中，EXIT 和 RETURN 語句的語義，分別使用退出例外 exitexception 和返回例外 returnexception 來定義。Modula3 的設計者認為語言實現，除了這種返回例外和退出例外之外，更應當以各種例外為代價，加速正常的結果產出；為每個引發的例外花費一千條指令，來為每個過程節約一條指令都是合理的。 塊與宣告 宣告介入一個常量、型別、變數、例外或過程的一個名字。這個名字的作用域是包含這個宣告的塊。一個塊可以出現為一個模組或過程的本體，或一個塊語句，Pascal 和 Modula2 沒有塊語句。一個塊有如下形式： Decls BEGIN S END 這裡的 Decls 是成序列的宣告，而 S 是一個語句，經常是順序複合語句即成序列的語句，它是這個塊的執行部份。這裡的 Decls 與 S 在縮排上對齊，是因為在 Pascal 語言家族中，可能含有巢狀過程宣告的宣告序列的位置相較於 ALGOL 60，從緊隨在關鍵字 BEGIN 之後轉移到了緊靠在其前面。一個塊的宣告可以介入一個名字最多一次，然而一個名字可以在巢狀的塊中重新宣告。在塊中這些宣告的次序，除了確定變數的初始化次序之外無關緊要。 一個 Modula3 程式規定了一個計算，它作用在一序列的叫做地點（location）的數字元件之上。變數是地點的一個集合，它依據這個變數的型別所確定的約定，表示一個數學上的。如果一個值可以由型別 T 的某個變數來表示，則稱謂這個值是 T 的一個成員，並且 T 包含這個值。 宣告為一個變數、型別、過程、或例外指定一個被稱為識別符號的作為名字。一個宣告應用於其上的程式區域，叫做這個宣告的作用域。作用域是可以巢狀的。一個識別符號的含義，由這個識別符號在其中宣告的最小的包圍作用域來確定。 型別宣告有如下形式：，這裡的 T 是一個識別符號，而 U 是一個型別或型別表示式。在需要型別的各種地方，通常允許型別表示式。 變數宣告有如下形式：，這裡的 id 是一個識別符號，T 是除了開放陣列之外的一個非空型別，而 E 是一個表示式。它聲明瞭 id 是型別 T 的一個變數，其初始值是 E 的值。 E 和 T 任何一個都可省略，但二者不能都省略。如果省略了 T，它採用 E 的型別。如果省略了 E，初始值是型別 T 的任意值。如果二者都存在，E 必須可賦值給 T。初始值是一種簡寫，等價於在隨後的塊的可執行部份開始處插入賦值 id E，如果多個變數有初始值，按它們宣告的次序插入它們的賦值。形式，是的簡寫。 宣告有如下形式：，這裡的 id 是一個識別符號，T 是一個型別，而 C 是一個常量表達式。它宣告 id 為具有型別 T 和值 C 的一個常量。 T 可以省略，在這種情況下 id 的型別是 C 的型別。如果 T 存在，則它必須包含 C。 值與型別 Modula3 的型別系統使用，而非 Modula2 的即型別構造子的每次出現產生一個新型別。在結構等價中，在如果兩個型別的定義在展開的時候，也就是在所有常量表達式都被替換為它們的值，並且所有型別名字都被替代為它們的定義的時候，變成相同的，則這兩個型別是相同的。在遞迴資料型別的情況下，這個展開是部份展開的無窮極限。 有三種序數型別：列舉、子範圍和整數型別，預定義瞭如下序數型別：INTEGER、LONGINT、CARDINAL（如同子範圍 0LAST INTEGER）、BOOLEAN（列舉 FALSE TRUE）和 CHAR（包含至少 256 個元素表示 ISOLatin1 程式碼的列舉）。整數和列舉元素合起來叫做序數值。序數值 v 如果是整數或擴充套件精度整數，則 v 的基礎型別分別是 INTEGER 或 LONGINT，否則 v 的基礎型別是包含它的那個唯一性的列舉型別。兩個序數如果有相同的值則二者相等。 有三種浮點型別：REAL、LONGREAL 和 EXTENDED，這些型別的屬性規定在對應的必要介面中。兩個浮點數如果定義它們的底層實現相同則二者相等。 一個引用值要麼是 NIL，要麼是一個叫做所引用者（referent）的變數的地址。預定義瞭如下引用型別：REFANY，它包含所有的有跟蹤的引用，ADDRESS，它包含所有的無跟蹤的引用，和 NULL，它只包含 NIL。Modula3 支援在執行時間的資料分配。分配操作有如下形式：，這裡的 T 是除了預定義的 REFANY、ADDRESS 或 NULL 之外的引用型別。兩個引用如果定址相同的地點則二者相等。 記錄是叫做這個記錄的欄位的命名變數的一個序列，記錄型別的宣告有如下形式：，在這裡的型別表示式中，RECORD 是型別構造子，而它的實際引數是欄位宣告的一個列表 FieldList，其中每個欄位都有如下形式：，這裡的欄位名字 fieldName 是一個識別符號，而欄位型別 Type 是除了開放陣列之外的非空型別，而欄位預設值 default 是一個常量表達式。形式，是的簡寫。兩個記錄如果有相同的欄位，並且對應的欄位都相等則二者相等。 在 Modula3 中的物件，非常類似於 Simula 67 中的物件：它們總是引用，它們擁有資料欄位和方法二者，並且它們有著單一繼承而非多重繼承。預定義瞭如下物件型別：ROOT，它是沒有欄位或方法的有跟蹤的物件型別，和 UNTRACED ROOT，它是沒有欄位或方法的無跟蹤的物件型別。 是一個名字，它指示某個給定引用型別的未知子型別。預定義了兩個：TEXT REFANY 和 MUTEX ROOT，它們分別表示文字串和互斥訊號量，它們的屬性分別規定於必要介面 Text 和 Thread 之中。 陣列是叫做這個陣列的元素的組成變數的有索引的蒐集。有兩種陣列型別，固定的和開放的。固定陣列的長度是在編譯時間確定的，開放陣列的長度是在執行時間分配確定的，這個長度此後不能改變。兩個陣列如果有相同的長度，並且對應的元素都相等則二者相等。 包裝型別的變量出現在記錄、物件或陣列中，佔據指定數量的位元，並毗鄰於前導的欄位或元素緊壓打包。包裝型別的宣告有如下形式：，這裡的 Base 是一個基礎型別，而 n 是整數取值的常量表達式。 集合是取自某個序數型別的值的蒐集。集合型別宣告有如下形式：，這裡的基礎型別 Base 是一個序數型別。兩個集合如果有相同的元素則二者相等。 不包含值的一個型別是空的，例如 10 是一個空型別。空型別可以用來建造非空型別，比如 SET OF 10。宣告一個空型別的一個變數是靜態錯誤。 所有的都有一個唯一的型別，但是一個值可以是很多型別的一個成員，例如值 6 是 09 和 INTEGER 二者的成員，因此論述 一個值的型別 將會是有歧義的。短語 x 的型別，意味著 表示式 x 的型別；然而短語 x 是 T 的成員，意味著 x 的值是 T 的成員。但在有一種情況下，一個值可以稱為有著一個型別：所有的物件或有跟蹤的引用值，包括了一個型別程式碼，它叫做這個引用值的分配型別。分配型別透過 TYPECASE 語句來測試。 語言規定提供了型別運算 BITSIZE 、BYTESIZE 和 ADRSIZE ，分別返回變數 x 或者型別 T 的那些變數的位元數目、8 位位元組的數目和可定址地點的數目。在所有情況下，x 必須是指定式，而 T 必須不是開放陣列型別，指定式 x 只在它的型別是開放陣列的時候求值。 序數型別 列舉型別宣告有如下形式：，這裡的 id 是各不相同的識別符號，型別 T 是 n 個值的有序集合，表示式 Tid_i 指示這個型別在遞增次序下的第 i 個值，空列舉 是允許的。 子範圍型別宣告有如下形式：，這裡的 Lo 和 Hi 是有相同的基礎型別的兩個序數值，T 的值是從 Lo 到 Hi 含二者所有的值，它們必須是常量表達式，如果 Lo 超過 Hi，則子範圍是空的。 每個不同的列舉型別介入新的一組值，而子範圍型別重複使用底層型別的值。例如： TYPE T1 A B C T2 A B C U1 T1AT1C U2 T1AT2C sic V A B 這裡的 T1 和 T2 是相同型別，因為它們有相同的展開定義。U1 和 U2 也是相同的型別，因為 T1C T2C。型別 T1 和 U1 卻是不同的，儘管它們包含相同的值，但是 T1 的展開定義是列舉，而 U1 的展開定義是子範圍。型別 V 是第三個型別，它的值 VA 和 VB 無關於值 T1A 和 T1B。 語言規定提供了支援序數型別的一些型別運算：對於序數型別 T，NUMBER T 返回在 T 中元素的數目，FIRST T 返回 T 的最小值，LAST T 返回 T 的最大值。ORD Tid 將一個列舉的元素 Tid，轉換成表示它在列舉次序中所處位置的整數，如果元素的型別是列舉 T 的子範圍，結果是元素在 T 內的位置，而非在子範圍內。VAL i T 將表示在列舉型別 T 中位置的整數 i，轉換成在這個列舉中此位置上的那個元素，如果 T 是列舉型別的子範圍，結果是在源出列舉型別的位置 i 上的元素，而非在子範圍內。如果 n 是型別 T 的一個整數，則有平凡的：ORD n VAL n T n。 陣列型別 固定陣列型別宣告有如下形式：，這裡的索引型別 Index 是序數型別，而元素型別 Element 是除了開放陣列之外的任何型別。開放陣列型別宣告有如下形式：，這裡的元素型別 Element 是任何型別。 陣列型別 T 的值，是元素型別為 Element 的陣列；對於固定陣列型別，這個陣列的長度是索引型別 Index 的元素數目；對於開放陣列型別，這個陣列的長度是任意的；開放陣列的索引型別是 INTEGER 子範圍 0n1，這裡的 n 是這個陣列的長度。開放陣列型別只能用作形式引數的型別，引用型別的所引用者，另一個開放陣列的元素型別，或作為陣列構造子中的型別。 多維陣列的形狀是它每一維的長度的序列。更精確的說，一個數組的形狀是它的長度跟隨著任何它的元素的形狀，非陣列的形狀是空序列。陣列如果有相同的型別和形狀，則它們是可賦值的。如果賦值的要麼來源要麼目標是開放陣列，則需要執行時間檢查。形如的表示式，是的簡寫。 如果 a 有陣列型別 T，則 a i 指示 a 的一個指定元素，它在陣列中的位置對應於 i 在索引型別中位置。形如 a i_1 i_n 的表示式，是 a i_1i_n 的簡寫。索引的解釋由一個數組的型別確定，而非它的值；陣列賦值改變陣列變數的值，而非它的型別。例如： VAR a ARRAY 13 OF REAL 10 20 30 b ARRAY 11 OF REAL a 這裡在 a 或 b 做元素值變更之前，a b 為 TRUE，儘管 a 1 10 而 b 1 30。 可以使用 NUMBER A，得到一個固定陣列型別的索引型別中的元素數目，使用 FIRST A 和 LAST A，分別得到一個固定陣列型別的索引型別的最小元素和最大元素。可以使用 NUMBER a，得到一個數組的索引型別中的元素數目，使用 FIRST a 和 LAST a，分別得到一個數組的索引型別的最小元素和最大元素，在這種情況下，表示式 a 只在它指示一個開放陣列的時候求值。 引用型別 一個引用型別要麼是有跟蹤的要麼是無跟蹤的。當到已分配的一段儲存的所有的有跟蹤的引用都消失時，系統對這段儲存進行垃圾回收。有跟蹤的引用型別以如下形式來宣告：，這裡的 Type 是任何型別。T 的值是到型別 Type 的變數的有跟蹤的引用，Type 叫做 T 的所引用型別。無跟蹤的引用型別以如下形式來宣告：，這裡的 Type 是任何無跟蹤的型別（這個限制在不安全模組中解除）。 兩個引用型別如果都是有跟蹤的或都是無跟蹤的，那麼它們有相同的引用類。一個一般性的型別是有跟蹤型別的條件為，它是有跟蹤的引用型別，其任何欄位型別是有跟蹤型別的記錄型別，其元素型別是有跟蹤型別的陣列型別，或其底層未包裝型別是有跟蹤型別的包裝型別。 在有跟蹤的和無跟蹤的二者情況下，關鍵字 REF 可選的可以前導上 BRANDED b，這裡的 b 是叫做銘牌（brand）的文字常量。銘牌用來區分原本上相同的型別，它們沒有其他語義效果。在一個程式中所有銘牌都必須是唯一性的。如果 BRANDED 出現而 b 缺席，系統自動的為 b 提供一個唯一的值。 分配操作返回 T 的所引用型別的一個新分配的變數的地址，如果 T 是物件型別，則返回到有配對的方法套件的一個新分配的資料記錄的引用。NEW 返回的引用不同於所有的現存引用。這個新引用的分配型別是 T。如果 T 的所引用型別為空則是一個靜態錯誤。如果 T 是到有 k 個開放維度的陣列的引用，NEW T 操作有如下形式：，這裡的這些 n 是指定新陣列在它的前 k 個維度上的長度的整數取值表示式。 所有的物件型別和有跟蹤的引用型別（包括 NULL）都有一個關聯的整數程式碼。不同的型別有不同的程式碼。給一個型別的程式碼對程式的任何單一執行都是常量，但對不同的執行可以不同。型別運算 TYPECODE T，返回型別 T 的這個程式碼，而 TYPECODE r，返回引用 r 的分配型別的這個程式碼。如果 T 是 REFANY，或者不是物件型別或有跟蹤的引用型別，則是一個靜態錯誤。型別運算 ISTYPE x T，測試 x 是否為 T 的成員，這裡的 T 必須是物件型別或有跟蹤的引用型別，而 x 必須可賦值給 T。 表示式 規定產生一個值或變數的一個計算。所有的表示式都有一個靜態確定的型別，它包含這個表示式可以產生的所有的值。在語法上，一個表示式要麼是一個運算數，要麼是應用於自身也是表示式的實際引數的一個運算。運算數是識別符號、或型別。透過遞迴的求值一個運算的實際引數並應用這個運算，來求值一個表示式。實際引數的求值次序，對除了短路求值的 AND 和 OR 之外的所有運算都是未定義的。 對一個過程的呼叫，在這個過程是返回一個結果的函式過程的時候，是稱為函式應用的一個表示式，這個表示式的型別是過程的結果型別。 Modula3 語言規定提供了字首算術運算：、，中綴算術運算：、、、、DIV、MOD，數值函式運算：ABS x、FLOAT x T、FLOOR x、CEILING x、ROUND r、TRUNC r、MAX x y、MIN x y，關係運算：、、 、、、，邏輯運算：NOT p、p AND q、p OR q，文字串接運算：a b，記憶體分配運算：NEW T ，集合運算：並集 、差集 、交集 、對稱差集 和隸屬關係測試 e IN s，它在序數 e 是集合 s 的元素的時候返回 TRUE。 表示式可建構自如下：、實數文字、和。集合、陣列和記錄有構造子表示式： S e_1 e_n，這裡的 S 是一個集合型別，而這些 e 是表示式或 lohi 形式的範圍。這個構造子指示型別為 S 的一個值，它包含列出的那些值和在列出的範圍中的那些值，這些 e、lo 和 hi 必須可賦值給型別 S 的元素型別。 A e_1 e_n，這裡的 A 是一個數組型別，而這些 e 是表示式。這個構造子指示型別為 A 的一個值，它包含遵循列出次序的這些列出元素，這些 e 必須可賦值給 A 的元素型別。如果 A 是多維陣列，則這些 e 必須自身也是陣列取值表示式。如果 A 是固定陣列型別，並且 n 至少為 1，則 e_n 可以跟隨著，，指出 e_n 的值按照需要重複任意多次來填滿這個陣列。 R Bindings，這裡的 R 是一個記錄型別，而 Bindings 是完全同於過程呼叫的關鍵字或位置繫結的一個列表。這個繫結列表會被重寫來適合 R 的欄位和預設值的列表，完全同於過程呼叫中的那些做為，記錄欄位名字扮演了過程形式引數的角色。這個構造子指示型別為 R 的一個值，它的欄位值由重寫後的這些繫結來指定。 表示式是一般性的表示式類的子集，所要求的限制使得可以靜態的求值這個表示式。在常量表達式中，除了 NEW 、解引用（顯式的或隱式的）、SUBARRAY 、TYPECODE 、NARROW 、ISTYPE 、ADR 和 LOOPHOLE 之外的所有運算都是合法的，唯獨可運用的過程，是在提供無符號字運算的 Word 介面中的函式。變數在常量表達式中，只能作為給 FIRST 、LAST 、NUMBER 、BITSIZE 、BYTESIZE 或 ADRSIZE 的實際引數出現，並且這個變數必須不是開放陣列型別的。文字和頂層過程常量在常量表達式中是合法的。 指定式 產生變數的表示式叫做指定式（designator）。常量表達式永遠不是指定式。指定式的型別是它產生的變數的型別。一個指定式依賴於上下文，可以指示要麼一個變數，要麼這個變數的值。比如，它作為賦值的左值時是變數，作為右值時是這個變數的值。一些指定式是隻讀的，它們不能用在可能改變這個變數的值的上下文中，並非只讀的指定式就是可寫的指定式。 一個識別符號是可寫的指定式的條件為，它被宣告為變數，是 VAR 或 VALUE 形式引數，TYPECASE 或 TRYEXCEPT 語句的區域性變數，或繫結到可寫指定式的 WITH 區域性變數。一個識別符號是隻讀的指定式的條件為，它是 READONLY 形式引數，FOR 語句的區域性變數，或繫結到非指定式或只讀的指定式的 WITH 區域性變數。只有如下運算可以產生指定式： r，這個運算叫做（dereferencing），它表示 r 的所引用者。表示式 r 總是可寫的指定式。如果 r 的型別是 REFANY、ADDRESS、NULL、物件型別或不透明型別，則是一個靜態錯誤；如果 r 是 NIL，則是一個必查的執行時間錯誤。 a i，這個運算叫做下標，它表示陣列 a 的值的第 i 1 FIRST a 個元素，比如說 a 的索引型別是 11，a 1 是這個陣列的值的第 1 1 1 個即第 3 個元素。表示式 a i 是否為指定式進而是否可寫同於 a。表示式 i 必須可賦值給 a 的索引型別。如果 a 是到陣列的引用，則這裡有隱含的解引用，即這裡的 a i 是 ai 的簡寫。 rf、of、Ix、om、Tm 和 Eid，這種點表示法運算叫選取（selection）。 rf 表示記錄 r 的指名欄位 f，表示式 rf 是否為指定式進而是否可寫同於 r。如果 r 是到記錄的引用，則這裡有隱含的解引用，即 rf 是 rf 的簡寫。 of 表示物件 o 的指名欄位 f，表示式 of 是可寫的指定式。 Ix 表示匯入的介面 I 的指名實體 x，如果 x 被宣告為變數，則表示式 Ix 是指定式並且總是可寫的。 om 表示物件 o 的指名方法 m，om 不產生指定式。 Tm 表示物件型別 T 的指名方法 m，Tm 不產生指定式。 Eid 表示列舉型別 E 的值 id，Eid 不產生指定式。 SUBARRAY a from for，它產生陣列 a 的越過前 from 個元素幷包含下 for 個元素的子陣列。SUBARRAY 不復制陣列，它是否為指定式進而是否可寫同於 a。如果 a 是多維陣列，SUBARRAY 只應用於頂層陣列。如果 from for 超過了 NUMBER a，則是一個必查的執行時間錯誤。 子型別規則 使用 T U 指示 T 是 U 的子型別，也就是 U 是 T 的超型別。子型別規則是：如果 T U，則型別 T 的所有值，都是型別 U 的值，反過來則不成立。 對於序數型別 T 和 U，T U 的條件為，它們擁有相同的基礎型別，並且所有的 T 的成員都是 U 的成員。就是說序數型別上的子型別，反映了在值集合上的子集關係。 對於陣列型別，一個數組型別 A 是一個數組型別 B 的子型別的條件為，它們有相同的最終元素型別，相同的維度數，並且對於每個維度，要麼二者都是開放的，要麼 A 是固定的而 B 是開放的，要麼它們都是固定的並有著相同的大小。 對於過程型別，T U 的條件為，它們除了形式引數名字、預設值和 RAISES 集合之外是相同的，並且 T 的 RAISES 集合包含在 U 的 RAISES 集合中。NIL 是所有的過程型別的一個成員。 對於包裝型別，BITS n FOR T 和 T 有相同的值，也就是說：BITS n FOR T T 並且 T BITS n FOR T。 對於集合型別，SET OF A SET OF B 的條件是 A B，就是說集合的子型別規則簡單的使用值集合規則。 對於引用型別有： NULL REF T REFANY NULL UNTRACED REF T ADDRESS 就是說，REFANY 和 ADDRESS 分別包含所有的有跟蹤的和無跟蹤的引用，NIL 是所有的引用型別的一個成員。這兩個規則也適用於加銘牌的型別。 對於物件型別有： ROOT REFANY UNTRACED ROOT ADDRESS NULL T OBJECT END T 就是說，所有物件都是引用，NIL 是所有的物件型別的一個成員，而所有的子型別都包括在它的超型別之中。第三個規則也適用於加銘牌的型別。 對於所有的 T，都有 T T。對於所有的 T U V，T U 並且 U V，蘊涵 T V。就是說 是自反和傳遞的。但是 T U 並且 U T，不蘊涵 T 與 U 是相同的，因為子型別關係不受形式引數名字、預設值和包裝的影響。 可賦值性 一個型別 T 可賦值（assignable）給型別 U 的條件是： T U，或者 U T 並且 T 是一個數組或除了 ADDRESS 之外的一個引用型別（這個限制在不安全模組中解除），或者 T 和 U 是至少有一個共同成員的序數型別。 在第一種情況下，沒有執行時間錯誤是有可能的。在第二種情況下，允許賦值一個 REFANY 到一個 REF T，還允許賦值一個 ARRAY OF T 到一個 ARRAY I OF T，這裡分別要求對引用的型別和陣列長度的執行時間檢查；可以使用型別運算 NARROW x T T，將物件型別或有跟蹤的引用型別的超型別變數當作其子型別的成員，這時需要執行時間檢查，介入它就是為了以安全的方式，將 REFANY 變數賦值給確知的實際型別 REF T。在第三種情況下，常規的範圍檢查就能確保特定的 T 的成員也是 U 的成員。 一個表示式 e 可賦值給一個變數 v 的條件是： e 的型別可賦值給 v 的型別，並且 e 的值是 v 的型別的一個成員，它不是一個區域性過程，並且如果它是一個數組，則有同 v 一樣的形狀。 一個表示式 e 可賦值給型別 T，如果 e 可賦值給型別 T 的某個變數。如果 T 不是一個開放陣列，這等同聲稱 e 可賦值給型別 T 的任何變數。 語句 執行一個語句產生一個計算，它可以正常產出結果（在可計算理論中稱為停機），發起一個例外，導致一個必查的執行時間錯誤，或無限迴圈。如果結果是一個例外，它可以可選的配對上一個實際引數。如果一個表示式作為一個語句的執行部份而求值，這個求值引發一個例外，則這個例外成為這個語句的結果。空語句是無操作的（noop），在語言報告中寫為。 過程呼叫在這個過程是真正過程的時候是一個語句。呼叫一個函式過程並丟棄它的結果使用 EVAL 語句，它有如下形式：EVAL e，這裡的 e 是一個表示式。它的效果是求值 e 並忽略其結果。RETURN 語句用於從過程中返回。 賦值語句有如下形式：，這裡的 v 是可寫的指定式，而 e 是可賦值給 v 所指示變數的表示式。賦值語句將 v 設定為 e 的值，v 和 e 的求值次序是未定義的，但 e 會在 v 更新之前求值。特別是，如果 v 和 e 是有交疊的子陣列，以沒有元素在被用作來源之前被用作目標的方式進行賦值。 順序複合語句有如下形式：S_1 S_2，它在 Modula2 中稱為 語句序列。一些程式設計者使用分號作為語句終結符（terminator），另一些程式設計者將它用作分隔符（separator）；Modula3 允許這兩種風格，語言報告將其用作分隔符。 塊語句有如下形式：，這裡的 Decls 是一序列的宣告，S 是一個語句。塊介入在 Decls 中宣告的常量、型別、變數和過程，並接著執行 S。宣告的名字的作用域是這個塊。 選擇控制結構 Modula3 提供了選擇控制結構 IF 和 CASE 語句。IF 語句有如下形式： IF B_1 THEN S_1 ELSIF B_2 THEN S_2 ELSIF B_n THEN S_n ELSE S_0 END 這裡的這些 B 是布林表示式，而這些 S 是語句。ELSE S_0 和每個 ELSIF B_i THEN S_i 都是可選的。IF 語句依次求值 B，直到某個 B_i 求值為 TRUE，則接著執行 S_i。如果沒有表示式求值為 TRUE，並且 ELSE S_0 存在，則執行 S_0。如果沒有表示式求值為 TRUE，並且 ELSE S_0 缺席，則 IF 語句是無操作的（noop）。Modula3 的 CASE 語句，不同於 Modula2 的同名語句，它有如下形式： CASE Expr OF L_1 S_1 L_n S_n ELSE S_0 END 這裡的 Expr 是型別為序數型別的一個表示式，而每個 L 是一個列表，這個列表構成自常量表達式，或用 e_1e_2 指示的常量表達式的範圍，它表示從 e_1 到 e_2 含二者的值。如果 e_1 超出了 e_2，這個範圍為空。如果兩個 L 表示的集合有交疊，或者任何常量表達式不是型別 Expr 的一個成員，則是一個靜態錯誤。ELSE S_0 是可選的。 CASE 語句求值 Expr。如果結果的值在任何 L_i 之中，則執行 S_i。如果這個值不在任何 L_i 之中，並且 ELSE S_0 存在，則執行它。如果這個值不在任何 L_i 中，並且 ELSE S_0 缺席，則發生一個必查的執行時間錯誤。一些程式設計者使用豎槓作為初始符（initiator），另一些程式設計者將它用作分隔符。Modula3 允許這兩種風格，語言報告將其用作分隔符。 分配型別測試 TYPECASE 語句有如下形式： TYPECASE Expr OF T_1 v_1 S_1 T_n v_n S_n ELSE S_0 END 這裡的 Expr 是型別為引用型別的一個表示式，這些 S 是語句，這些 T 是引用型別，而這些 v 是識別符號。如果 Expr 有型別 ADDRESS，或者任何 T 不是 Expr 的型別的子型別，則為一個靜態錯誤。ELSE S_0 和每個 v 都是可選的。如果 v_i 缺席，形式 T_1 T_n S，是 T_1 S T_n S 的簡寫。 TYPECASE 語句求值 Expr，如果結果的引用值，是任何列出的型別 T_i 的成員，則針對其中最小的 i，執行 S_i。NIL 是所有引用型別的一個成員，因此 NULL 情況只有首先出現才能起作用。如果這個值不是列出的這些型別的一個成員，並且 ELSE S_0 存在，則執行它。如果這個值不是列出的這些型別的一個成員，並且 ELSE S_0 缺席，則發生一個必查的執行時間錯誤。每個 v_i 宣告型別為 T_i 的一個變數，並且它的作用域是 S_i。如果 v_i 存在，它在執行 S_i 之前被初始化為 Expr 的值。 可以使用 TYPECASE 語句測試型別為 REFANY 或物件的一個表示式的值的引用型別，比如寫一個過程 ToText r REFANY TEXT，在其中測試 r 的值是 NULL、REF BOOLEAN 和 REF INTEGER 中的哪一個型別。 迴圈控制結構 Modula3 提供了迴圈控制結構 FOR、LOOP、WHILE 和 REPEAT 語句，和必須在字面上包圍在這四個迴圈語句中，用於從迴圈中退出的 EXIT 語句。語句，迴圈直到 S 中有一個發生。語句，被定義為： LOOP IF B THEN S ELSE EXIT END END 語句，被定義為： LOOP S IF B THEN EXIT END END FOR 語句有如下形式：，這裡的 id 是一個識別符號，而 first 和 last 是有相同基礎型別的序數表示式，step 是整數取值的表示式。而 S 是一個語句。BY step 是可選的，如果省略，step 預設為 1。識別符號 id 指示其作用域是 S 的一個只讀變數，其型別是 first 和 last 共同的基礎型別。FOR 語句的語義，可如下這樣用 WHILE 和 WITH 語句精確的定義為一個塊： VAR i ORD first done ORD last delta step BEGIN IF delta 0 THEN WHILE i done DO WITH id VAL i T DO S END INC i delta END ELSE WHILE i done DO WITH id VAL i T DO S END INC i delta END END END 這裡的 T 是 id 的型別，i、done 和 delta 代表不出現在 FOR 語句中的變數。從 FOR 語句的這個定義可以看出，如果一個 FOR 迴圈的上界是 LAST INTEGER 或 LAST LONGINT，就應當將它改寫為 WHILE 迴圈來避免溢位。 With 語句 Modula3 的 WITH 語句，無關於 Modula2 的同名語句，它有如下形式：，這裡的 id 是一個識別符號，e 是一個表示式，而 S 是一個語句。WITH 語句聲明瞭具有作用域 S 的 id，作為變數 e 的別名，或作為值 e 的只讀名字。表示式 e 在進入 WITH 語句的時候被求值一次。一個單一的 WITH 語句可以包含多個繫結，它們順序的求值，就是說，等價於。 WITH 語句可類比於某種過程呼叫 P e，這裡的 P 被宣告為： PROCEDURE P mode id typeof e BEGIN S END P 這裡的算符 typeof 只是個示意，它不在語言規定之中；如果 e 是可寫的指定式，則 mode 是 VAR，否則 mode 是 READONLY。在 WITH 語句和呼叫 P e 之間唯一的區別為，出現在 WITH 語句內的自由變數、RETURN 和 EXIT，是在 WITH 語句所在的上下文中解釋的，而非在新增加的 P 的上下文中。 Modula3 語言報告使用 WITH 語句定義其他語句，比如，INC 和 DEC 語句分別有如下形式：和，這裡的 v 指示一個序數型別的變數，而 n 是可選的一個整數取值表示式，如果省略 n 則預設為 1，這兩個語句分別等價於和，這裡的 T 是 v 的型別，而 x 代表不出現在 n 中的變數。 例外 例外宣告有如下形式：EXCEPTION id T，這裡的 id 是一個識別符號，而 T 是除了開放陣列之外的一個型別，它聲明瞭 id 是具有實際引數型別 T 的例外。如果省略了 T，這個例外不接受實際引數。例外宣告只允許出現在介面和模組的最外層作用域之中。所有的宣告的例外都是各不相同的。 RAISE 語句有兩種形式，沒有實際引數的形式：，這裡的 e 是不接受實際引數的一個例外，它的結果是發起例外 e；具有實際引數的形式：，這裡的 e 是接受實際引數的一個例外，而 x 是可賦值給 e 的實際引數型別的一個表示式，它的結果是引發具有配對實際引數 x 的例外 e。 Modula3 的例外處理，基於了 TRYEXCEPT 語句。採用類似的塊系統的有 Delphi、Python、Scala 和 Visual BasicNET。 TRYEXCEPT 語句有如下形式： TRY Body EXCEPT id_1 v_1 Handler_1 id_n v_n Handler_n ELSE Handler_0 END 這裡的 Body 和每個 Handler 都是語句，每個 id 指名一個例外，而每個 v_i 是一個識別符號。ELSE Handler_0 和每個 v_i 都是可選的。每個 v_i 宣告一個變數，其型別是例外 id_i 的實際引數型別，而它的作用域是 Handler_i。如果 v_i 缺席，形式 id_1 id_n Handler，是 id_1 Handler id_n Handler 的簡寫。 TRY 子句執行 Body。如果結果是正常的，則忽略 EXCEPT 等子句。如果 Body 引發任何列出的例外 id_i，則執行 Handler_i。在處理具有配對實際引數 x 的例外 id_i 的時候，v_i 在執行 Handler_i 之前被初始化為 x。如果 Body 引發任何其他例外，並且 ELSE Handler_0 存在，則執行它。在這兩種情況的任何之一下，TRYEXCEPT 語句的結果是選出的處理器的結果。如果 Body 引發未列出的例外，而 ELSE Handler_0 缺席，則 TRYEXCEPT 語句的結果是 Body 引發的例外。 Modula3 還提供 TRYFINALLY 語句，它有如下形式：，它執行語句 S_1 接著執行語句 S_2。如果 S_1 的結果是正常的，則 TRY 語句的結果等價於 S_1 S_2。如果 S_1 的結果是例外，並且 S_2 的結果是正常，則在 S_2 執行之後，重新發起來自 S_1 的例外。如果二者的結果都是例外，則 TRY 語句的結果是來自 S_2 的例外。 在 Modula3 中，和語句的語義，分別被定義為發起叫做 exitexception 和 returnexception 的例外。exitexception 不接受實際引數，returnexception 接受任意型別的實際引數，程式不能顯式的命名這些例外。語句，非正式的等價於： TRY S S S EXCEPT exitexception skip END 過程 過程型別 一個過程要麼是 NIL，要麼是有如下構成的三元組： 過程體，它是一個語句。 簽名，它有如下形式 formal_1 formal_n R RAISES S，這裡的每個 formal_i 是形式引數，R 是結果型別，S 是 RAISES 集合（這個過程可以引發的例外的集合）。 環境，它是在解釋過程體中變數名字方面有關的作用域。 形式引數有如下形式：，這裡的： Mode 是引數模態，它可以是 VALUE、VAR 或 READONLY。如果省略了 Mode，它預設為 VALUE。 Name 是命名這個形式引數的識別符號。形式引數名字必須是各不相同的。 Type 是這個形式引數的型別。 Default 是一個常量表達式，它是這個形式引數的預設值。如果 Mode 是 VAR，則 Default 必須省略，否則 Default 和 Type 中任何一個都可以省略，但不能二者都省略。如果省略了 Type，它採用 Default 的型別。如果二者都存在，Default 的值必須是 Type 的一個成員。 形式，是的簡寫。 VAR 形式引數繫結到對應的實際引數所指示的變數上，也就是說它是別名。對於 VAR 形式引數，實際引數必須是可寫的指定式，它的型別同於形式引數的型別，或者在 VAR 陣列形式引數的情況下，它可賦值給這個形式引數。 VALUE 形式引數繫結到具有未用的位置的一個變數上，並且它被初始化為實際引數對應的值。對於 VALUE 或 READONLY 形式引數，實際引數是可賦值給形式引數型別的任何表示式，並且放開了針對賦值區域性過程的禁止。 READONLY 形式引數，如果實際引數是指定式並且有與形式引數相同的型別，或者是可賦值給形式引數的型別的一個數組型別，則被當作 VAR 形式引數對待，它的只讀語義體現在指定這個指定式為只讀的，否則被當作 VALUE 形式引數對待。 在簽名中，如果省略了 R，則這個過程是真正（proper）過程，否則為函式過程；如果省略了 RAISES S，則假定它為 RAISES 。一個過程發起未包括在 RAISES 集合中的一個例外，是一個必查的執行時間錯誤，如果語言實現將這個執行時間錯誤對映成一個例外，則這個例外隱含的包括在所有的 RAISES 子句中。 過程宣告 有兩種形式的過程宣告：只允許出現在介面中的，和只允許出現在模組中的，這裡的 id 是一個識別符號，sig 是過程簽名，而 B 是一個塊。在一個模組的最外層作用域內宣告的過程是頂層過程，其他過程是區域性過程。區域性過程可以作為形式引數傳遞但不能被賦值，因為在棧實現下，區域性過程在包含它的棧楨被彈出後會成為無效的。 過程型別宣告有如下形式：，這裡的 sig 是簽名規定。一個過程 P 是過程型別 T 的一個成員，或稱為是它的一個值的條件為，它是 NIL，或者它的簽名被 T 的簽名所含蓋（cover）。這裡的簽名 sig_A 含蓋簽名 sig_B 的條件是： 它們有相同數目的形式引數，並且對應的形式引數有相同的型別和模態。 它們有相同的結果型別，或者都沒有結果型別。 sig_A 的 RAISES 集合包含 sig_B 的 RAISES 集合。 過程常量是宣告為過程的一個識別符號。過程變數是宣告為具有過程型別的一個變數。例如： PROCEDURE P txt TEXT P BEGIN IOPut txt END P VAR q PROCEDURE txt TEXT Q P 聲明瞭過程常量 P 和過程變數 q。兩個過程如果有一致的閉包，就是說它們涉及相同的過程體和環境，則二者相等即有相同的值。形式引數名字和預設值，影響一個過程的型別即簽名，而非這個過程的值。將一個過程常量賦值給一個過程變數，改變這個它的值，而非它的型別。比如上例中有：P q 為 TRUE。預設的形式引數的解釋，由一個過程的型別來確定，而非這個過程的值。比如上例子中：P 列印 P，而 q 列印 Q。 過程呼叫 過程呼叫有如下形式：P Bindings，這裡的 P 是一個過程取值的表示式，而 Bindings 是關鍵字或位置繫結的一個列表。關鍵字繫結有如下形式：name actual，這裡的 actual 是一個表示式，而 name 是一個識別符號。位置繫結有如下形式：actual，這裡的 actual 是一個表示式。當關鍵字和位置繫結混合在一個呼叫中的時候，位置繫結必須前導於關鍵字繫結。如果繫結列表為空，圓括號仍然是需要的。 繫結列表要如下這樣重寫，來適合 P 的型別簽名：首先，每個位置繫結 actual，若為 Bindings 中的第 i 個繫結，則透過補充上第 i 個形式引數的名字，轉換成關鍵字繫結增加到關鍵字繫結列表中。其次，對於有預設值並且在第一步之後沒有被繫結的每個形式引數，將它的形式引數的名字 name 和它的預設值 default，形成關鍵字繫結 name default 增加到關鍵字繫結列表。重寫成的關鍵字繫結列表必須只繫結形式引數，並且必須只繫結每個形式引數正好一次。 執行過程呼叫，需要求值過程取值表示式 P 和它的實際引數，繫結形式引數，並執行過程體。P 和它的實際引數的求值次序是未定義的。呼叫一個未定義或 NIL 過程，是一個必查的執行時間錯誤。呼叫具有過程體 B 的真正過程，在綁定了實際引數之後等價於： TRY B EXCEPT returnexception skip END 而呼叫具有過程體 B 的函式過程等價於： TRY B 錯誤：沒有返回值 EXCEPT returnexception v 結果成為 v END 遞迴定義 對於常量、型別或過程宣告 N E、變數宣告 N E、例外宣告 N E 或揭示 N E，如果 N 出現在 E 的任何部份展開之中，則它是遞迴的。對於省略了型別的變數宣告 N I，如果 N 出現在 I 的型別 E 的任何部份展開中，則它是遞迴的。允許這種宣告的條件，是 N 在 E 的任何部份展開中所有的出現為如下三者之一：在型別構造子 REF 或 PROCEDURE 的某個出現之內，在型別構造子 OBJECT 的一個欄位或方法型別之內，或者在一個過程體之內。下面是合法的遞迴宣告的例子： TYPE RealList REF RECORD val REAL link RealList END ListNode OBJECT link ListNode END IntList ListNode OBJECT val INTEGER END T PROCEDURE n INTEGER p T EXCEPTION E PROCEDURE RAISES E PROCEDURE P b BOOLEAN BEGIN IF b THEN P NOT b END END P 特徵性技術 Modula3 的設計者認為 Modula2 最成功的特徵，是提供了在模組之間的顯式介面，故而介面在 Modula3 中保留而在本質上沒有變化。到模組的介面，是披露了模組公開部份的宣告蒐集，而未聲明於介面中的模組中的東西是私有的。模組匯入它所依賴的介面，而匯出它所實現的介面（在 Modula3 中可以是多個介面）。 在現代程式語言的實現下，一個抽象型別的值，被表示一個物件，它的操作由叫做物件的方法的過程值的一個套件來實現。一個新的物件型別，可以定義為現存型別的子型別，在這種情況下新型別擁有舊型別的所有方法，並且可能還有新的方法（繼承）。新型別可以為舊方法提供新的實現（覆蓋）。物件型別和 Modula2 的的組合，產生了一個新事物：部份不透明（partially opaque）型別，這裡的一個物件的一些欄位在一個作用域內是可見的，而其他的是隱藏的。 泛型模組是一種模板，在其中一些匯入的介面被當作形式引數，它們在例項化泛型的時候要繫結到實際介面。不同的泛型例項是獨立編譯的，原始碼程式被重複使用，而編譯後的程式碼對不同例項通常是不同的。為保持簡單性，在 Modula3 中泛型被限制在模組層面，泛型的過程和型別不孤立存在，並且泛型形式引數必須都是完全的介面。 將計算分解入併發程序（或執行緒）中是關注點分離的基本方法。Modula2 提供的執行緒很弱，本質上相當於協程。Modula3 採用了霍爾的監視器，它是併發程式設計的更堅實基礎。在設計中加入了簡化的 Mesa 同步原語，它足夠成功而在實質上沒有改變的結合入了 Modula3。 一個語言特徵是不安全的，如果它的濫用可以破壞執行時系統，使得程式的進一步執行不忠實於語言的語義，不安全特徵的一個例子，是沒有邊界檢查的陣列賦值。一個安全的程式的一個錯誤，可以導致計算中止，並給出執行時間錯誤資訊或給出錯誤解答，但它不會導致計算分崩離析。Modula3 在這個領域裡跟從 Cedar，接受只在顯式的標記為不安全的模組中才允許的少量不安全特徵。 模組化 介面中的宣告，除了任何變數初始化必須是常量，和過程宣告必須只能指定簽名而不能有過程體之外，同於在塊中的宣告。介面有如下形式： INTERFACE id Imports Decls END id 這裡的 id 是命名這個介面的識別符號，Imports 是一序列的匯入語句，而 Decls 是一序列的宣告。在 Decls 中的名字和可見的匯入的名字必須是各不相同的。兩個或更多個介面形成匯入環是靜態錯誤。典型的介面定義，通常為每個介面定義一個數據結構（記錄或物件）以及任何的支援過程。 模組除了實體名字的可見性之外，就像是一個塊。一個實體在一個塊中是可見的，如果它被宣告在這個塊中，或在某個包圍的塊中；而一個實體在一個模組中是可見的，如果它被宣告在這個模組中，或在這個模組所匯入或匯出的一個介面中。模組有如下形式： MODULE id EXPORTS Interfaces Imports Block id 這裡的 id 是命名這個模組的一個識別符號，Interfaces 是這個模組匯出的那些介面的不同名字的一個列表，Imports 是一序列的匯入語句，而 Block 是一個塊，它是模組體。名字 id 必須重複於終結模組體的 END 之後。EXPORTS Interfaces 可以省略，在這種情況下 Interfaces 預設為 id，即模組將預設匯出相同名稱的介面。Modula3 中的匯出 EXPORTS，與 Modula2 中的匯出 EXPORT 無關，它在概念上對應於 Modula2 的 實現。 如果模組 M 匯出了介面 I，則在 I 中宣告的所有名字在 M 中是不加以限定而可見的。一個模組 M 匯出一個介面 I，可以重新宣告在這個介面中宣告的一個或多個過程，為其提供過程體。在 M 中的簽名，必須被在 I 中的簽名所含蓋。要確定在對這個過程的呼叫中的關鍵字繫結的解釋，在 M 內使用 M 中的簽名，在其他地方使用 I 中的簽名。除了重新宣告匯出的過程之外，在 Block 的頂層中宣告的名字，可見的匯入的名字，和在匯出的介面中宣告的名字必須是各不相同的。 一個程式的模組和介面的名字叫做全域性名字。查詢全域性名字的方法是依賴於實現的，比如透過檔案系統查詢路徑。一個模組或介面 X 匯入一個介面 I，從而使得在 I 中宣告的實體和揭示在 X 中可見，但不包括 I 所匯入的那些。一個模組 M 使用了介面 I，如果 M 匯入或匯出了 I，或者 M 使用了匯入 I 的一個介面。Modula3 中所有的編譯單元，要麼是介面要麼是模組。任何編譯單元都可以使用 IMPORT 語句從其他介面匯入識別符號。與其他語言的包含功能不同，任何識別符號都可以追蹤到它的起源位置。 IMPORT 語句有如下的典型使用形式：，它匯入全域性名字為 I 的介面，並給它一個同樣的區域性名字，從而使用點表示法訪問介面中的實體（類似於訪問記錄中的欄位）。比如介面中的主要型別按慣例命名為 T，則使用它時採用的限定形式為 IT。如果匯入介面的名字與模組內的其他實體的名字發生衝突，則可以使用這樣的形式給與它不同的區域性名字。 IMPORT 語句還有如下的另一種形式：，它為在介面 I 中宣告為 N 的實體，介入一個區域性名字 N，比如：，並且不加限定的使用它，比如：。區域性繫結優先於全域性繫結，例如：，為全域性名字為 JN 的實體介入了局部名字 N。非法使用相同的區域性名字兩次是靜態錯誤。 一個程式是模組和介面的蒐集，包含了任何它的模組或介面所匯入或匯出的所有介面，並且在其中沒有重複定義的過程、模組或介面。執行一個程式的效果是執行它的所有模組的模組體。模組的執行次序受到初始化規則的約束：如果模組 M 依賴於模組 N 並且 N 不依賴於 M，則 N 的模組體將先於 M 的模組體執行。這裡的模組 M 依賴於模組 N，如果 M 使用了 N 匯出的一個介面，或者 M 所依賴的一個模組依賴於 N。 其模組體最後執行的模組叫做主模組。在初始化規則不能唯一的確定它的情況下，語言實現提供了指定這個主模組的方法，即主模組是匯出 Main 的模組，它的內容是依賴於實現的。程式執行在主模組終止的時候終止，即使併發的控制執行緒仍在執行。 下面是介面與模組的一個規範性的例子，是有隱藏表示的一個公開堆疊： INTERFACE Stack TYPE T REFANY PROCEDURE Create T PROCEDURE Push VAR s T x REAL PROCEDURE Pop VAR s T REAL END Stack MODULE Stack REVEAL T BRANDED OBJECT item REAL link T END PROCEDURE Create T BEGIN RETURN NIL END Create PROCEDURE Push VAR s T x REAL BEGIN s NEW T item x link s END Push PROCEDURE Pop VAR s T REAL VAR res REAL BEGIN res sitem s slink RETURN res END Pop BEGIN END Stack 如果多於一個模組需要此堆疊的表示，則應當把它轉移到私有介面中，從而在需要它的任何地方的都可以匯入它： INTERFACE Stack 同上 END Stack INTERFACE StackRep IMPORT Stack REVEAL StackT BRANDED OBJECT item REAL link StackT END END StackRep MODULE Stack IMPORT StackRep Push、Pop 和 Create 同上 BEGIN END Stack 物件型別 一個物件要麼是 NIL，要麼是到有配對的方法套件的一個數據記錄的引用，方法套件是接受這個物件作為第一個實際引數的那些過程的一個記錄。這個資料記錄可以包含經由物件型別的子型別介入的增加欄位，這個套件可以包含經由子型別介入的增加方法。物件賦值是引用賦值。要複製一個物件的資料記錄到另一個物件，這些欄位必須單獨的賦值。 Modula3 意圖保持採用物件這個最簡單的術語，而非在其他面嚮物件語言中對應的術語類。物件型別宣告採用如下形式： TYPE T ST OBJECT Fields METHODS Methods OVERRIDES Overrides END 這裡的 ST 是可選的超型別，如果省略則預設為 ROOT，Fields 是完全如同記錄型別那樣的欄位宣告的一個列表，Methods 是方法宣告的一個列表，而 Overrides 是方法覆蓋的一個列表。在欄位和方法宣告中介入的名字，必須相互不同，並且不同於在覆蓋宣告中的名字。T 的欄位構成自 ST 的欄位和隨後的新宣告的欄位。T 的方法構成自經過 OVERRIDES 中的覆蓋修改的 ST 的方法，和隨後的 METHODS 中宣告的方法。T 有著同 ST 一樣的引用類。 關鍵字 OBJECT 可選的可以前導上 BRANDED 或 BRANDED b 來給物件加銘牌，使之唯一而避免結構等價，這裡的 b 是文字常量。其含義同於非物件的引用型別，b 被省略時，系統自動生成唯一性的一個字串。 方法宣告有如下形式：m sig proc，這裡的 m 是個識別符號，sig 是過程簽名，而 proc 是頂層過程常量。方法宣告指定了 T 的方法 m 有簽名 sig 和值 proc。如果省略了 proc 假定它為 NIL。如果 proc 非空，它的第一個形式引數必須是預設的模態 VALUE，並有著 T 的某個超型別的型別（包括且經常是 T 自身），並且去除了第一個形式引數結果就是 sig 所含蓋的簽名。 方法覆蓋（override）有如下形式：m proc，這裡的 m 是超型別 ST 的方法的名字，而 proc 是頂層過程常量。方法覆蓋指定了 T 的方法 m 是 proc，並非指定 STm。如果 proc 非空，它的第一個形式引數必須是預設的模態 VALUE，並有著 T 的某個超型別的型別（包括且經常是 T 自身），去除了 proc 第一個形式引數結果就是 ST 的 m 方法所含蓋的簽名。舉例說明： TYPE Super OBJECT a INTEGER METHODS p END Sub Super OBJECT b INTEGER END PROCEDURE ProcSuper self Super PROCEDURE ProcSub self Sub 這裡的過程 ProcSuper 和 ProcSub 是型別 Super 和 Sub 的物件的 p 方法的候選值。例如： TYPE T1 Sub OBJECT OVERRIDES p ProcSub END TYPE T2 Super OBJECT OVERRIDES p ProcSuper END 聲明瞭具有 Sub 資料記錄和預期一個 Sub 的 p 方法的一個型別。T1 是 Sub 的有效的子型別。 聲明瞭具有 Super 資料記錄和預期一個 Super 的 p 方法的一個型別。T2 是 Super 的有效的子型別。 TYPE T3 Sub OBJECT OVERRIDES p ProcSuper END TYPE T4 Super OBJECT OVERRIDES p ProcSub END 聲明瞭具有 Sub 資料記錄和預期一個 Super 的 p 方法的一個型別。因為所有 Sub 都是 Super，這個方法不挑剔要放入的物件。 嘗試宣告具有 Super 資料記錄和預期一個 Sub 的 p 方法的一個型別，因為不是所有 Super 都是 Sub，這個方法很挑剔要放入的物件。T4 的宣告是個靜態錯誤。 如果 T 是物件型別或到記錄的引用，NEW T 操作有如下形式：，這裡的 Bindings 是用來初始化新欄位的關鍵字繫結的一個列表，不允許位置繫結。每個繫結 f v 將欄位 f 初始化為值 v。如果 T 是物件型別，則 Bindings 還可以包括形如 m P 的方法覆蓋，這裡的 m 是 T 的一個方法而 P 是一個頂層過程常量。是的語法糖。 如果 o 是一個物件，則 of 指示在 o 的資料記錄中名為 f 的資料欄位。of 是可寫的指定式，它的型別是這個欄位的所宣告的型別。如果 m 是 o 方法之一，以 om Bindings 形式的過程呼叫，指示執行 o 的 m 方法，這等價於：o 的 m 方法 o Bindings。 如果 T 是物件型別而 m 是 T 的方法的名字之一，則 Tm 指示 T 的 m 方法。它的過程型別的第一個實際引數有型別 T，而第一個實際引數對應的形式引數名字是未指定的，因此在呼叫 Tm 時，第一個實際引數必須按位置來指定，不能用關鍵字。這種表示法便於子型別方法呼叫它的某個超型別的對應方法。 在子型別中的欄位或方法遮蓋（mask）了在超型別中的任何同名的欄位或方法。要訪問被遮蓋的欄位，使用型別運算 NARROW x T 來將子型別變數當作超型別的成員，這裡的 T 必須是物件型別或有跟蹤的引用型別，而 x 必須可賦值給 T。NARROW x T T 在檢查了 x 是 T 一個成員之後返回 x，如果檢查失敗則發生執行時間錯誤。 下面的例子展示了在宣告新方法和覆蓋現存方法之間的不同，首先宣告如下： TYPE Super OBJECT METHODS m ProcSuper END SubOverridden Super OBJECT OVERRIDES m ProcSub END SubExtended Super OBJECT METHODS m ProcSub END VAR a NEW Super b NEW SubOverridden c NEW SubExtended 然後可以用 am 啟用 ProcSuper a，用 bm 啟用 ProcSub b，用 cm 啟用 ProcSub c，如此呼叫在覆蓋和擴充套件之間沒有區別。但是擴充套件的 c 的方法套件有兩個方法，而覆蓋的 b 的方法套件只有一個方法，這可以透過使用 NARROW x T 將子型別的變數 b 和 c 視為超型別 Super 的成員來披露：NARROW b Superm 啟用 ProcSub b，NARROW c Superm 啟用 ProcSuper c。 物件不能，因為在語言實現中，一個物件變數的靜態型別不確定它的資料記錄的型別。物件型別確定了關乎資料記錄欄位和方法套件的超型別鏈的字首的那些型別。 實現 下面是語言設計者提出的物件的一種可能實現的梗概，一個物件可以表示為它的資料記錄的第一個字的地址。前面的字儲存一個物件頭部，它包含一個唯一於物件型別的型別程式碼。這些型別程式碼是小型整數，對每個物件型別和每個有跟蹤的引用型別都有一個程式碼。在物件頭部之前的字，儲存到這個物件的方法套件的一個引用。如果這個物件沒有方法，這個字可以省略。這還允許物件共享方法套件，這是常見情況。如果 o 是一個物件，d 是它的資料欄位之一，而 m 是它的方法之一，則在這種表示下： od 是 Mem o d om 是 Mem Mem o 2 m TYPECODE o 是 Mem o 1 這裡假定了欄位和方法以自然方式表示為偏移量。進一步的問題是如何高效的測試一個物件 o 是否有著型別 T，這是 NARROW 和 TYPECASE 語句所需要的。NARROW 的最簡單實現，是維護一個以型別程式碼為索引的陣列 st，st tc 是其型別程式碼為 tc 的物件型別的超型別的型別程式碼，如果它沒有超型別則為 NIL。要測試 o 是否是一個 T，使用一個迴圈來計算 T 的型別程式碼是否出現在如下序列之中： TYPECODE o st TYPECODE o st st TYPECODE o NIL 這個序列可以稱為 o 的型別的超型別路徑，而它的長度可稱為 o 的型別的深度。利用上每個型別的深度都是編譯時間確定的，因此可以同相應的型別程式碼一起儲存的事實，可以有更快速的 NARROW 實現。如果 T 的型別程式碼，出現在型別 U 的超型別路徑上，它就該在位置 depth U depth T 上。如果每個型別的超型別路徑都是順序陣列，這意味著 NARROW 可以用恆定時間實現。因為超型別路徑通常不太長，這是一個有吸引力的策略。在不常見的物件型別有非常長的超型別鏈的情況下，只有這個鏈的直到某個極大長度的一個字首，會被順序的儲存。在執行時間，這個深度差如果超出這個鏈的順序儲存的長度，實現必須回退到連結串列。 不透明型別及其披露 （opaque）型別宣告有如下形式：，這裡的 T 是識別符號，而 U 是指示一個引用型別的表示式。它將名字 T 介入為不透明型別，並披露了 U 是 T 的超型別。 Modula3 的揭示（revelation）機制，將關於一個不透明型別的資訊，介入到一個作用域之內，不同於其他宣告，揭示不介入新的名字。不同的作用域，可以披露（reveal）關於一個不透明型別的不同的資訊。例如，某個不透明型別，在一個作用域內知曉為 REFANY 的子型別，在其他的作用域內可以知曉為 ROOT 的子型別。 不透明型別名字所指示的實際型別叫做具體型別。T 的具體型別，必須披露於程式的其他地方。在物件宣告中，如果 ST 被宣告為不透明型別，則只在知曉 ST 的具體型別為物件型別的作用域內，T 的宣告是合法的。如果 T 被宣告為不透明型別，則只在完全知曉 T 的具體型別，或者知曉它為物件型別的作用域內，NEW T 是合法的。 揭示分為兩種：部份的和完全的，一個程式可以包含一個不透明型別的任意多個部份揭示，但必須包含唯一的一個完全揭示。 部份揭示有如下形式：，這裡的 V 是型別表示式（可能就是個名字），而 T 是被宣告為不透明型別的一個識別符號（可能有限定）。它披露了 V 是 T 的超型別。在任何作用域內，對一個不透明型別披露的超型別，必須是在子型別關係下是線性有序的。就是說，如果披露了 T U1 和 T U2，則必須也要披露要麼 U1 U2 要麼 U2 U1。是合法的非遞迴宣告。 完全揭示有如下形式：，這裡的 V 是型別表示式（不能就是個名字），它的最外層型別構造子，是有銘牌的一個引用或物件型別，而 T 是被宣告為不透明型別的一個識別符號（可能有限定）。這個揭示指定了 V 是 T 的具體型別。在任何作用域內，披露為 T 的超型別的任何型別，都必須是 V 的超型別，否則是一個靜態錯誤。不同的不透明型別有不同的具體型別，因為 V 包含了一個銘牌並且在程式中所有的銘牌都是獨一的。是非法的遞迴宣告。 揭示只允許用在介面和模組的最外層作用域內。在介面中的揭示可以被匯入到任何需要它的作用域之內。揭示提供了向客戶隱藏實現細節的，在概念上簡單清晰卻非常強力的機制，例如： INTERFACE I TYPE T ROOT PROCEDURE P x T T END I INTERFACE IRep IMPORT I REVEAL IT MUTEX BRANDED OBJECT count INTEGER END END IRep INTERFACE IClass IMPORT I REVEAL IT MUTEX END IClass 匯入 I 的編譯單元見到的 IT 是 ROOT 的不透明子型別，因而被限制為可以分配型別 IT 的物件，把它們傳遞給 IP，或宣告 IT 的子型別。匯入 IRep 的編譯單元見到的 IT 是具體型別，它是有擴充套件的 count 欄位的 MUTEX 的子型別。匯入 IClass 的編譯單元見到的 IT 是 MUTEX 的不透明子型別，因而可以鎖定型別 IT 的物件。 泛型 在泛型介面或模組中，某些匯入的介面名字被當作形式引數，它們在泛型被例項化的時候要繫結到實際介面上。泛型介面及其例項有如下左側的形式，並等價於右側定義的普通介面： GENERIC INTERFACE G F_1 F_n Body END G INTERFACE I G A_1 A_n END I INTERFACE I IMPORT A_1 AS F_1 A_n AS F_n Body END I 這裡的 G 是命名這個泛型介面的一個識別符號，F_1 F_n 是叫做 G 的形式匯入的識別符號的一個列表，而 Body 同在非泛型介面中一樣，是一序列匯入和隨後的一序列宣告。這裡的 I 是這個例項的名字，而 A_1 A_n 是 G 的形式匯入要繫結的實際介面的一個列表。 泛型模組及其例項有如下左側的形式，並等價於右側定義的普通模組： GENERIC MODULE G F_1 F_n Body END G MODULE I EXPORTS E G A_1 A_n END I MODULE I EXPORTS E IMPORT A_1 AS F_1 A_n AS F_n Body END I 這裡的 G 是命名這個泛型模組的一個識別符號，F_1 F_n 是叫做 G 的形式匯入的識別符號的一個列表，而 Body 同在非泛型模組中一樣，是一序列的匯入和隨後的一個塊。這裡的 I 是這個例項的名字，E 是由 M 匯出的介面的一個列表，而 A_1 A_n 是 G 的形式匯入要繫結的實際介面的一個列表。EXPORTS E 可以省略，在這種情況下它預設為 EXPORTS I。泛型模組自身沒有匯出，它們只在被例項化時提供。 泛型介面及其對應的泛型模組（與 C 模板一樣）可以輕鬆定義和使用抽象資料型別，但粒度在模組級別，裸露的型別 INTEGER 或 REAL 不能使用，相比之下，它們在 C 模板中可以使用。例如，可以定義泛型堆疊： GENERIC INTERFACE Stack Elem 這裡的 ElemT 不是開放陣列型別 TYPE T REFANY PROCEDURE Create T PROCEDURE Push VAR s T x ElemT PROCEDURE Pop VAR s T ElemT END Stack GENERIC MODULE Stack Elem REVEAL T BRANDED OBJECT n INTEGER a REF ARRAY OF ElemT END PROCEDURE Create T BEGIN RETURN NEW T n 0 a NIL END Create PROCEDURE Push VAR s T x ElemT BEGIN IF sa NIL THEN sa NEW REF ARRAY OF ElemT 5 ELSIF sn LAST sa THEN WITH temp NEW REF ARRAY OF ElemT 2 NUMBER sa DO FOR i 0 TO LAST sa DO temp i sa i END sa temp END END sa sn x INC sn END Push PROCEDURE Pop VAR s T ElemT BEGIN DEC sn RETURN sa sn END Pop BEGIN END Stack 然後使用介面例如 IntegerElem，對其進行例項化，只要這個介面定義了泛型模組所需的屬性即可： INTERFACE IntegerElem TYPE T INTEGER END IntegerElem INTERFACE IntStack Stack IntegerElem END IntStack MODULE IntStack Stack IntegerElem END IntStack 面向物件 Modula3 下的面向物件程式設計，經常採用部份不透明型別，它透過如下慣用法來宣告：，這裡的不透明型別 T，支援在隨後定義的物件型別中的欄位和方法，而不會披露 T 的確切結構，也不披露 T 可能支援的其他方法。 下面的例子，定義一個介面 Person，具有按習慣約定命名的兩個型別，匯出型別 T，和公開物件型別 Public，這裡聲明瞭 T 是 Public 的不透明子型別，Public 具有兩個方法 getAge 和 init ；隨後是 Person 介面的完全實現： INTERFACE Person TYPE T Public Public OBJECT METHODS getAge INTEGER init name TEXT age INTEGER T END END Person MODULE Person REVEAL T Public BRANDED OBJECT name TEXT age INTEGER OVERRIDES getAge Age init Init END PROCEDURE Age self T INTEGER BEGIN RETURN selfage END Age PROCEDURE Init self T name TEXT age INTEGER T BEGIN selfname name selfage age RETURN self END Init BEGIN END Person 要建立一個新的 PersonT 物件，要使用內建操作 NEW ，並呼叫方法 init ： VAR jim NEW PersonTinit Jim 25 下面是整數堆疊的例子： INTERFACE IntegerStack TYPE T Public OBJECT Public OBJECT METHODS init T push x INTEGER pop INTEGER END END IntegerStack MODULE IntegerStack REVEAL T Public BRANDED OBJECT n INTEGER a REF ARRAY OF INTEGER OVERRIDES init Init push Push pop Pop END PROCEDURE Init self T T BEGIN selfn 0 selfa NIL RETURN self END Init PROCEDURE Push self T x INTEGER BEGIN IF selfa NIL THEN selfa NEW REF ARRAY OF INTEGER 5 ELSIF selfn LAST selfa THEN WITH temp NEW REF ARRAY OF INTEGER 2 NUMBER selfa DO FOR i 0 TO LAST selfa DO temp i selfa i END selfa temp END END selfa selfn x INC selfn END Push PROCEDURE Pop self T INTEGER BEGIN DEC selfn RETURN selfa selfn END Pop BEGIN END IntegerStack 建立新堆疊在這裡的部份不透明型別實現下為：，在上述的不透明型別實現下為：。而壓入一個數在這裡的部份不透明型別實現下為：，在上述的不透明型別實現下為：。 多執行緒 語言支援多執行緒和線上程間的同步。在執行時庫（m3core）中有一個必要介面叫做 Thread，它支援採用分叉會合模型的多執行緒應用。這裡還預定義不透明型別 MUTEX 被用來同步多個執行緒，並保護共享資料免於具有可能損害或競爭條件的同時訪問。MUTEX 是一個物件，因此可以從它派生其他物件。 LOCK 語句有如下形式：，這裡的 S 是一個語句，而 mu 是一個表示式，它等價於： WITH m mu DO ThreadAcquire m TRY S FINALLY ThreadRelease m END END 這裡的 m 表示不出現在 S 中的一個變數。LOCK 語句介入一個互斥鎖要鎖定的塊，並暗含著在程式碼執行軌跡離開這個塊時的解鎖它。 不安全標記 某些功能被認為是不安全的，編譯器無法再保證結果是一致性的（例如，當與 C 程式語言交接時）。在 INTERFACE 或 MODULE 前面加上字首關鍵字 UNSAFE，可用於告訴編譯器啟用語言的某些不安全的低階功能。例如，在 UNSAFE 模組中，使用 LOOPHOLE 將整數的諸位元複製成浮點 REAL 數，使用 DISPOSE 釋放無跟蹤的記憶體。 一個介面是內在安全的，如果在安全模組中使用這個介面，無法產生不核查的執行時間錯誤。如果匯出一個安全介面的所有的模組都是安全的，編譯器保證這個介面的內在安全性。如果匯出一個安全介面的任何模組是不安全的，就要程式設計者而非編譯器，去做這種保證了。安全介面匯入不安全介面，或安全模組匯入或匯出不安全介面，都是靜態錯誤。匯入不安全介面的編譯單元本身必定也是不安全的。 對其他程式語言的影響 儘管 Modula3 沒有獲得主流地位，DECSRC M3 發行的某些部份做到了。可能最有影響的一部份是網路物件庫，它形成了 Java 包括了網路協議的最初的遠端方法呼叫（RMI）實現的基礎。在 Sun 從通用物件請求代理架構（CORBA）標準轉移到基於 IIOP 的協議的時候才被放棄。Java 關於遠端物件的垃圾收集的文件仍提及了 Modula3 網路物件為其先驅性工作 Garbage Collection of Remote Objects Java Remote Method Invocation Documentation for Java SE 8 。 Python 從 Modula3 借鑑了模組系統、例外系統和關鍵字引數，Python 的類機制受到 C 和 Modula3 的啟發。Nim 利用了 Modula3 的某些方面比如有跟蹤和無跟蹤的指標。 引用 外部連結 CM3 Implementation Website Modula3 Home Page mirror Modula3 Language definition Building Distributed OO Applications Modula3 Objects at Work Michel R Dagenais Draft Version January 1997 ObjectOriented Data Abstraction in Modula3 Joseph Bergin 1997 Category 面向物件的程式語言 Category 系統程式語言 CategoryModula 程式語言家族 Category1988 年建立的程式語言