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 is not optimised for the writer's convenience. 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
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
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 →