Scientific programming in Modula-9 — first steps

↖ contents

1 — Hello, and why M9 exists

M9 exists because of an afternoon in which the same small program — a reader for a scientific data format — was written twice, in two respected compiled languages, and both versions shipped bugs their compilers had every reason to catch. Each failure was catalogued; each became a language rule; the failing programs live on in the repository's museum/, where the build proves, forever, that they no longer compile. Nothing in M9 is there because it is elegant. Everything is there because its absence, somewhere, cost somebody a result.

Before the first example, the philosophy in one paragraph. M9 optimises for the reader, not the writer — for the trust and the re-run, not the first draft. It is verbose where verbosity is information: every import is named, every error a procedure can raise is in its signature, every allocation says which pool owns it, every conversion between types is written out. You get exactly what is written — and when what is written is wrong, the compiler refuses it, by name, instead of running something plausible. This is a deliberate trade. Code is written once, but it is reviewed, re-read, re-run and audited many times, increasingly by people (and machines) who did not write it. A language that front-loads the effort of saying precisely what you mean repays it every time anyone — a colleague, a reviewer, an AI agent, you in two years — has to establish what the code actually does.

The first program

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
MODULE C1Hello ;

(* Chapter 1.  A program is a MODULE whose body becomes the entry
   point.  The EXCEPT block at the bottom is the root of the whole
   error story: any exception nothing below handled arrives here,
   and a program says what it does about failure at the one frame
   with no caller left to tell.                                     *)

IMPORT Io ;

VAR
  i : I64 ;

BEGIN
  Io.WriteLine ('hello from M9') ;
  FOR i := 1 TO 3 DO
    Io.Write ('measurement ') ;
    Io.WriteI64 (i) ;
    Io.WriteLine ('')
  END
EXCEPT
| ValueRange :
    Io.ErrLine ('a value did not fit') ;
    Io.Halt (1)
END C1Hello.
C1Hello.m9

expected output:

hello from M9
measurement 1
measurement 2
measurement 3

Things to notice, because they generalise:

What "checked" means here

The founding bug: a GNU Modula-2 build, at optimisation level 2, executed a[42] on an array of ten elements and printed the word "unreachable". The checks existed at -O0; the flag removed them. M9's answer is that checks are part of what a program MEANS — there is no build in which they are absent, any more than there is a build in which + means subtraction.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
MODULE C1Bounds ;

(* Chapter 1.  The bug that founded the language: a GNU Modula-2
   build at -O2 EXECUTED a[42] on an array of ten and printed
   "unreachable".  In M9 the check is part of what the program
   MEANS, not a compiler flag: this loop runs off the end on
   purpose, and the access raises IndexError instead of reading
   whatever lies past the array.                                    *)

IMPORT Io ;

VAR
  a   : ARRAY 10 OF I64 ;
  i   : I64 ;
  sum : I64 ;

BEGIN
  FOR i := 0 TO 9 DO
    a [i] := i * i
  END ;
  sum := 0 ;
  FOR i := 0 TO 12 DO      (* three past the end, deliberately *)
    sum := sum + a [i]
  END ;
  Io.WriteLine ('never reached')
EXCEPT
| IndexError :
    Io.Write ('IndexError refused the read; the sum so far was ') ;
    Io.WriteI64 (sum) ;
    Io.WriteLine ('')
END C1Bounds.
C1Bounds.m9

expected output:

IndexError refused the read; the sum so far was 285

The loop deliberately runs to 12 on an array of 10. The read of a[10] raises IndexError; the handler reports the sum of the ten legal elements (285 = 0² + 1² + … + 9²) and the program exits cleanly. No flag, no sanitizer, no "debug build" — this is the only behaviour the program can have.

The cost of this, measured on real scientific workloads, is a few percent. The cost of not having it was the museum.

← Previous: installing the compiler · Next: strong typing →