Scientific programming in Modula-9 — first steps

↖ contents

3 — Definition and implementation

A module has two parts, usually kept in one file: the DEFINITION, which is everything a caller may rely on, and the IMPLEMENTATION, which is nobody else's business. The definition is a contract in the enforceable sense: the checker compares every implemented procedure against its declared signature and refuses drift, and a promised procedure that is never implemented is an error, not a linker surprise or a TODO.

Here is a small library — temperature handling with a physical floor — followed by a client. Notice that the definition carries the EXCEPTION with its payload fields, and every procedure's complete RAISES list:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Temps.m9

Two halves, one file, and the boundary is real: Zero is a constant of the implementation; no client can see it. The comments under each definition are not just prose either — m9c --doc renders them, per procedure and per parameter, into the module's reference page; the library documentation you will meet in later chapters is generated exactly that way, from files exactly like this.

What the contract refuses

Change the implementation's parameter type and the module no longer compiles:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
X3Sig.m9

the compiler refuses:

16:1 X3Sig.ToKelvin: signature differs from definition:
    definition     (celsius: F64) : F64
    implementation (celsius: F32) : F64

Omit a promised procedure and it is named:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
X3Missing.m9

the compiler refuses:

13:1 X3Missing.ToFahrenheit: declared in the definition but not implemented

The client's side of the contract

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
32
33
34
C3Use.m9

expected output:

mean of the series: 278.07 K
TooCold: -300.0 is below -273.15

The handler arm Temps.TooCold (got, limit) binds the payload the exception was declared with, so the message can say WHICH reading broke WHAT limit — errors are values here, with structure, not strings fished out of a log. And the handler is not optional politeness: Mean declares RAISES TooCold, this program's body calls it, and the checker required this frame to either declare the exception onward or answer for it. Delete the handler and the module joins the X-files.

The deeper point of this chapter: the signature is the review. A reader deciding whether to trust Temps.Mean reads one declaration and knows its inputs, its output, its failure modes, and (chapter 5) who owns its storage. Nothing else in the file can contradict that declaration and still compile.

← Previous: strong typing · Next: memory, pools and strings →