Arnt Gulbrandsen
About meAbout this blog

Branded variables and so on

Why was Modula 3 so good?

The question has bothered me enough that I bought a new copy of Systems Programming with Modula 3 to reread. I reread, and was no wiser.

I liked the brevity of the language description. The designers explictly tried to make the language simple enough to describe in fifty pages. That may have something to do with the clarity of Modula 3 code.

I liked many of the minor features. I've mentioned the 31-bit integers before. Branded native types are another.

In Modula 3, you could define a variable as (I forget the exact syntax) branded msec cardinal timeout; and get protection against unit confusion. If you branded a string as untrustworthy user-supplied input, you couldn't just assign it to an untagged string. If you branded an integer as msec, you couldn't just pass it to a function which accepted a seconds-tagged integer. That half-type gave a pleasant amount of protection against careless mistakes.

I seem to be saying that I liked Modula 3 because it was a compiled object-oriented language with simple syntax, sufficiently expressive, with some good features and no bad ones. Put that way, I admit that's my kind of language.


Integer variables in Modula-3

Modula 3 is perhaps my favourite language. It has (had — it's practically dead now) most of what I like about java, most of what I like about c++, most of what I like about modula 2, and some unique features.

One of its little greatnesses is in the integer type system.

In modula 3, an unsigned integer is 31 or 63 bits long (as I recall, there are two unsigned integer types, although a tutorial I found on the web now mentions only one). Signed integers are 32 or 64 bits, so if a is a signed integer, a=b always works, regardless of whether b is signed or unsigned.

a=b does not throw exceptions, a=b; b=a does not change the value of b, and the cost of that is merely that you have to start using 64-bit variables at 2147483648 instead of at 4294967296.

Update: I want to expand on that, and compare it to java. The language designers of both java and modula3 understood that confusion or sloppiness with regard to signed and unsigned integers was a significant source of bugs in c/c++. Java solved it by not having unsigned integers, modula3 solved it by reducing their bit width by 1.5-3%.

I have seen many java programs that either output long to formats or protocols where only unsigned numbers are legal, or that read into long when the format clearly says 64 bits unsigned, so I think the java solution isn't very good. They chopped off the problematic feature and instead people use a misfit type. Sometimes it works: In this example it likely works because the sender too, uses a java long, so the so-called 64 bits unsigned ID is really 63-bit. I am not sure whether this kind of bug is preferable to the kind of signed/unsigned bugs in classic c.

Modula3, on the other hand, made the less obvious choice of leaving one bit at zero. The CPU registers are 32 or 64 bits wide, modula3 restrains programs to using 31 or 63 bits. As a result, programmers can still express the unsigned nature of many numbers using the type system, without sign problems. Subtle, well-considered, 97% good.