Last week, Niklaus Wirth has died, aged 89. I’ll leave the summary of his many achievements to more knowledgeable authors. His achievements are remarkable, no doubt, even though I think many are more than under-appreciated outside an “inner circle”, since he was not “mainstream”. Not that he wanted to be, and he stayed firm with his principles and convictions all his career. Everyone knows about Pascal – but else? But for me his way of thinking is more important, as far as I can tell from his publications and speeches. I have re-read a few of them in the past week. So let me just touch on a few points from a personal perspective. He was a real, old-school engineer, in the best sense of that expression.
I had attended his introductory classes at ETH Zurich during my initial year of my studies toward a Master of Science degree, in the faculty of Electrical Engineering. Using, of course, Pascal. By then, there existed no computer science studies in Switzerland. NW was a driving force to establish such courses, and degrees, at ETH. It happened right when I was there. In fact, I could have switched to this completely new curriculum, mid-studies, with my classes already done fully accepted. That is, the new computer science course was started somewhere in the middle of what would become the full curriculum later. I did not switch. Don’t ask.
One of NW’s1 principle was simplicity and understanding. Full, in-depth understanding. He did not want to educate students to just become programmers. Today, computer science classes seem to have a heavy focus on teaching one or the other programming language, and the corresponding frameworks, since the “industry” expects graduates to enter their jobs and be fully “productive” immediately. That’s why programming languages and frameworks used in said industries are used to teach the basics, irrespective of the fitness of these languages for that purpose. A compiler for the language C (or C++) comprises hundreds of thousands of lines of code. The complexity of the language itself – the standard is more than a thousand pages – and this amount of code are simply not conducive for an in-depth understanding of the principles and foundations. I am pretty sure there are not many people on this planet who fully understand the GNU C/C++ compiler. I use C/C++ just as an example for what is “normal” these days. Lots of complexity, if actually justified or not.
One of NW’s focal points, and goal, was to enable the students to understand the foundations of programming language design, and its impact on the compiler, and vice versa. And by extension the frameworks and tools around a programming language. That’s what a university-level computer science course should provide, not just to learn to program. Sure, a CS graduate must be able to program, but that comes “with the job”, when learning how to write a compiler, for example. Or a file system, even if a simple one. In general, I strongly believe that any university degree should provide foundational knowledge and skills, and the ability to contribute to such foundations, not only to know how to apply learned know-how, cookbook-style. NW was always striving to teach just that, not only in the field of programming languages, but all the areas delineated by the topic “computer”. Hardware and software. Their interaction. And even more in-depth, not just understanding, but being able to construct, up from the very foundations. He insisted that each concept, each feature, needs to be proven valuable through engineering. Implementing stuff. Hands-on. Stepwise improvements through experience. No, most graduates will not go an design programming languages, and write compilers in their jobs, but this kind of foundational know-how and skills is then easily extended to the actual problems at hand, using the programming language and framework du jour. Essential vs. ephemeral, as NW called it.
In my professional life, I have come in contact with NW’s work when I was tasked to write a program for a controller of a power station for telephone exchanges. The programming language was Modula-2, which I had never used before. Nothing a two week crash course cannot fix, one-to-one with an expert. I have loved that language. It was miles ahead of other languages, in particular as regards – you guessed it – modularisation, with strict type-checking across module boundaries. Import declarations get translated automatically into dependencies for the build system. No makefiles and all that nonsense. And it’s readable. Ever tried to read a complex C program that someone else has written? It’s probably just me, but I get a headache quickly.2 So much clutter and visual noise. Functions, or even global variables, that become available via header files, but in the program text it’s not easy to discern which file defines and implements them. Don’t get me started on the required “header guards”. What year is this?3
Always striving to simplify to the max, NW then decided that he had gone too far with certain language elements of Modula-2, which were tricky to handle in a reliable and fast compiler, and he designed a simpler derivative, Oberon. In his Turing Award Lecture in February 1985 he said, “I secretly confess that this Modula-2 compiler is already at the limits of comprehensible complexity”.4 That compiler was about 5,000 lines of code. He always wanted to be able to implement a compiler himself, alone, for any of his languages. I also think he loved writing compilers. In his view, that is the only way of finding out if a language is well-designed, since it’s easy to specify some useful-looking feature, but which is difficult to implement, leading to bloat, tricky edge cases, and an expensive burden at run-time. One of the benchmarks he formulated and used for the quality of a language-compiler combo – and the two must always be considered and designed together – was the time it takes a compiler to compile itself.
There’s a C/C++ software development kit for the RP2040 and the Pico. The “hello world” program for a microcontroller is the “blinker”, ie. switching an LED on and off periodically. Obviously, there’s not a lot of code for the essence of that program. Re-building, ie. re-compiling each involved file, and linking the blinker example program that comes with the SDK takes about ten seconds.
If I re-build the analogous program in Oberon with the Astrobe compiler and linker, the time is about 200 milliseconds. Now that’s a good language-compiler combo. The compiler is about 3,000 lines of code, if memory serves. Any software engineer with some perseverance can understand that. This “one person must be able to fully understand” motto extends through a lot of NW’s work. Case in point, the whole Oberon system. I can understand it fully, and you can as well. Ideal for teaching and learning. Experimenting. It recompiles in seconds.
I often wish I had someone like NW looking over my shoulder, and ask, How exactly do you justify that additional code and complexity with respect to the benefit of the new or improved feature?! I have read that he was usually pretty reluctant to allow to add more code and complexity without really good justifications. Finding a fit of the solution’s complexity with the problem’s. Which is a sound attitude, and approach, and more parsimony would benefit many areas of today’s world of software and computers.
You know, old-school real engineering.
NW is the signature you find in all modules he has created. ↩︎
For example, try to understand the Lua interpreter/compiler. Good luck, if you’re a mere mortal. ↩︎
I know, I know, there are other languages that are more advanced. You know, sane. But I dwell in the embedded domain now, and there C/C++ is dominant. ↩︎
And he continued, “… and I would feel utterly incapable of constructing a good compiler for Ada.” ↩︎