Hello World in Modula-2
Your first Modula-2 program - the classic Hello World example with Docker setup using GNU Modula-2 (gm2)
Every programming journey starts with Hello World. Let’s write our first Modula-2 program using the GNU Modula-2 compiler (gm2), which is now part of GCC.
The Code
Create a file named hello.mod:
| |
Understanding the Code
Modula-2 programs are clean, modular, and structured. Let’s break down each part:
MODULE Hello;- Declares a module named Hello (the program entry point)FROM StrIO IMPORT WriteString, WriteLn;- Imports specific procedures from the StrIO libraryBEGIN- Marks the start of the module body (executable statements)WriteString("Hello, World!");- Outputs the text stringWriteLn- Outputs a newline characterEND Hello.- Closes the module (must match the module name and end with a period)
The Import Statement
Modula-2 uses qualified imports to control the namespace:
| |
This imports only WriteString and WriteLn from the StrIO module, making them available directly. You could also write:
| |
This keeps the module prefix, making the code origin explicit.
Module Structure
A Modula-2 program module has this structure:
| |
Notice the period after Name - all Modula-2 modules (program, definition, and implementation) end with the module name followed by a period.
Case Sensitivity
Unlike Pascal, Modula-2 is case-sensitive:
MODULEis different frommodule(use uppercase for keywords)Hellois different fromhello- Convention: Keywords in uppercase, identifiers in MixedCase
Comments
Modula-2 uses Pascal-style comments:
| |
Running with Docker
The easiest way to run Modula-2 without installing gm2 locally is with Docker using our pre-built image that includes the GNU Modula-2 compiler:
| |
Understanding the Docker Command
gm2- The GNU Modula-2 compiler (part of GCC)-o hello- Output executable namedhellohello.mod- Input source file (.mod = Modula-2 module)./hello- Run the compiled executable
The gm2 command automatically:
- Compiles the source to object code
- Links with the Modula-2 runtime library
- Produces an executable
Running Locally
If you have GCC 13+ with gm2 installed:
| |
Installing gm2
macOS (Homebrew):
| |
Ubuntu/Debian (GCC 13+):
| |
Fedora/RHEL:
| |
From Source:
| |
Expected Output
Hello, World!
Clean and simple - exactly what you’d expect!
Alternative Approaches
Modula-2’s standard library offers several ways to output text:
Using Individual Character Output
| |
This demonstrates arrays and loops, but WriteString is much simpler.
Using Write and WriteString Together
| |
Write (from StdIO) outputs a single character, WriteString (from StrIO) outputs a string.
With Constants
| |
Constants declared between imports and BEGIN.
With Variables
| |
Variables declared in the VAR section.
The .mod and .def Files
Modula-2 programs use two file types:
.mod (Module Implementation)
Contains:
- Program modules (like our Hello World)
- Implementation modules (code for definition modules)
- Module initialization code
.def (Definition Module)
Contains:
- Module interfaces (exported types, procedures, constants)
- Type declarations visible to clients
- Procedure signatures (no implementation)
Our simple Hello World only needs a .mod file since it’s a standalone program module. As programs grow, you’ll create libraries with separate definition (.def) and implementation (.mod) files.
Program Structure
A minimal Modula-2 program requires:
- MODULE declaration - Define the program name
- Optional IMPORT clauses - Bring in needed modules
- Optional declarations - Constants, types, variables, procedures
- BEGIN keyword - Start module body
- Statements - Actual program logic
- END clause - Close the module with name and period
Example with Declarations
| |
Notice:
- Constants declared in
CONSTsection - Variables declared in
VARsection - Strings are character arrays
- Each section appears before
BEGIN
Compilation Process
When you run gm2 -o hello hello.mod, several things happen:
hello.mod → hello.o (Object file)
→ hello (Executable)
Separate Compilation Steps
You can also compile manually:
| |
With Multiple Modules
For larger programs:
| |
Common Beginner Mistakes
Missing Period After Module Name
| |
Wrong Import Syntax
| |
Mismatched Module Name
| |
Forgetting Semicolons
| |
Case Errors
| |
Wrong File Extension
Modula-2 requires specific extensions:
hello.m2- ❌ Not standardhello.m- ❌ Not recognized by gm2hello.mod- ✅ Correct for moduleshello.def- ✅ Correct for definitions
Compiler Options
Useful gm2 compilation flags:
| |
Dialect Selection
gm2 supports multiple Modula-2 dialects:
| |
Our Hello World works with all dialects.
Standard Library Modules
Common Modula-2 library modules:
StrIO (gm2 base library)
String input and output:
WriteString()- Output stringWriteLn- Output newlineReadString()- Input string
NumberIO (gm2 base library)
Numeric input and output:
WriteInt()- Output integerWriteCard()- Output cardinalReadInt()- Input integer
Storage
Dynamic memory allocation:
ALLOCATE()- Allocate memoryDEALLOCATE()- Free memory
Strings
String manipulation:
Length()- String lengthConcat()- Concatenate stringsCompare()- Compare strings
MathLib0
Mathematical functions:
sqrt()- Square rootsin(),cos()- Trigonometricexp(),ln()- Exponential/logarithm
Why Modula-2 for Hello World?
Even in this simple example, you see Modula-2’s philosophy:
- Explicit Imports - No hidden dependencies or globals
- Clear Structure - MODULE declaration, BEGIN/END blocks
- Module Name Redundancy -
END Hello.catches copy-paste errors - Qualified Access -
StrIO.WriteStringshows exactly where functions come from - Strong Typing - Even strings have explicit types (character arrays)
These features become invaluable in large systems where Modula-2 was designed to shine.
A Bit of History
Modula-2 was created by Niklaus Wirth (1934-2024), who also designed Pascal. The name “Modula” comes from modular programming - the language’s central concept.
In the late 1970s, when Modula-2 emerged, most systems programming was done in assembly or C. Modula-2 proved you could write operating systems, compilers, and device drivers in a high-level language with strong type safety. The entire Lilith workstation OS was written in Modula-2.
Today, Modula-2’s module system concepts live on in Go (co-designed by Wirth’s student Robert Griesemer) and influenced many subsequent module systems in modern languages.
Performance Note
Modula-2 compiles to native machine code. The gm2 compiler uses GCC’s optimization backend, so compiled Modula-2 benefits from the same optimization passes used for C and C++. Most type safety checks happen at compile time rather than runtime, keeping overhead low.
Standard Output Libraries
Different Modula-2 implementations have different I/O modules:
gm2 Base Libraries (our example)
| |
ISO Style
| |
Classic PIM Style (requires -flibs=ulm,pim flag)
| |
gm2 supports multiple library sets - use -fiso for ISO mode, or -flibs=ulm,pim for classic PIM InOut module.
Next Steps
Now that you’ve written your first Modula-2 program, you can explore:
- Variables and Data Types - Learn about Modula-2’s strong type system
- Module System - Create reusable definition and implementation modules
- Pointers and Dynamic Memory - Work with dynamic data structures
- Procedures and Functions - Build modular, reusable code
Key Takeaways
- Modula-2 uses explicit imports via
FROM module IMPORTclauses - Programs are modules with
MODULE/BEGIN/ENDstructure - Module names must match in the END clause with a period
- Case sensitive - keywords in uppercase, identifiers in MixedCase
- gm2 is part of GCC and available in modern GCC distributions
.modfiles contain program and implementation modules.deffiles contain definition modules (interfaces)- Comments use
(* ... *)delimiters
Troubleshooting
“gm2: command not found”
Your GCC version is older than 13, or your GCC installation was not built with Modula-2 support. Either:
- Install GCC 13+ with gm2 from your package manager
- Build GCC from source with
--enable-languages=m2 - Use Docker with
codearchaeology/modula-2:latestimage (note: the officialgcc:latestDocker image does not include gm2)
“cannot find module ‘InOut’”
The InOut module is in the Ulm compatibility libraries, not the default gm2 base libraries. Either use StrIO instead (recommended), or specify the Ulm library set:
| |
“syntax error”
Check:
- Keywords are UPPERCASE (
MODULE, notmodule) - Module name matches in
END Hello. - Period after module name in END clause
- Semicolons after IMPORT and before BEGIN
Strange compilation errors
Try explicitly setting the dialect:
| |
Running Today
All examples can be run using Docker:
docker pull codearchaeology/modula-2:latest
Comments
Loading comments...
Leave a Comment