This paper was originally written for my course CIS*4500 - Programming Languages, taken at the University of Guelph. The paper I'm reviewing is a Computer Science Publication by Edsger Dijkstra
It would be modest to call Edsger W. Dijkstra (May 1930 - August 2002) simply a programmer, computer scientist or software engineer. Dijkstra was; the father of structured programming, a visionary and a pioneer in computer science. Many of his teachings and ideologies are considered fundamental, and have had a lasting affect on software design for the last half a century. On August 14th, 1972, Dijkstra presented a brief, yet timeless lecture at the ACM Annual Conference in Boston, entitled The Humble Programmer. Within this talk, Dijkstra analyzes and criticizes the modern (at least in 1972) approaches to programming, development, and language design. His writing is intuitive enough to be understandable to any reader and yet perceptive enough to continuously provide novel meanings after each reread. Dijkstra artfully and implicitly states the necessary conditions for his…
“Vision that, well before the seventies have run to completion, we shall be able to design and implement the kind of systems that are now straining our programming ability at the expense of only a few percent in man-years of what they cost us now, and that besides that, these systems will be virtually free of bugs”.
Unfortunately, Edsger W. Dijkstra’s vision never came to fruition. On the contrary, 46 years later, the software crisis is arguably more cancerous than previously described, if not due to worse design practises than at least due to increased reliance on software systems. As we continue to struggle to refine our systems and design practises, we have started to put more weight on the arguments made in The Humble Programmer. Entire industries, markets, careers and textbooks (including principles such as KISS, Agile, and Test-Driven Development) have been created in an effort to actualize Dijkstra’s vision. However, for the purposes of this exploration of the text, instead in jumping off of a bridge in an attempt to dissect what I can only describe as one of Computer Science’s few spiritual texts, I’ll discuss a single sentence which aptly describes our short-comings in the design of programming languages, both in the seventies and today;
“Another lesson we should have learned from the recent past is that development of ‘richer’ or ‘more powerful’ programming languages was a mistake in the sense that these baroque monstrosities, these conglomerations of idiosyncrasies, are really unmanageable both mechanically and mentally.”
This sentence prefaces Dijkstra’s argument that languages were beginning to be produced that programmers couldn’t intellectually handle. Which inevitably causes a programmer to “concentrate on the vagaries of the programming language and distracts him [or her] from the complexity of the problem”. But does Dijkstra’s argument hold weight? Were languages already starting to balloon and overcomplicate the problems they were attempting to solve? How does adding features and complexity to a language diminish it’s productivity? In what way do these problems translate to contemporary languages? And most importantly how do we finally learn the lesson that Dijkstra describes in the above quote, so that we can end the software crisis once and for all.
“[T]hese conglomerations of idiosyncrasies, are really unmanageable both mechanically and mentally.”
To understand why Edsger W. Dijkstra’s believed that programming languages may have become unmanageable, it’s first necessary to build a brief foundation; what is the point and purpose of a programming language? While there are a variety of programming languages with a wide range of features and specifications, languages in general are meant to serve as a means of efficient communication between humans and computers. Computers use a series of boolean bits as an instruction set for logical operations, equations, data storage and more. While that may seem complicated, it is orders of magnitude more difficult to parse the series of ambiguous, emotional and illogical grunts and noises than make up human language. But until the day that we can teach machines to understand our language (or at least they can teach us to fluently speak theirs), we will have to settle for designing and maintaining languages to act as the middle ground. Inhabiting this delicate region however is a task in and of itself. Languages need to find a balance between including too few and too many features, then implement them properly. While, again, this topic deserves an entire paper itself, in its place a brief parable will have to suffice.
If programming is indeed a craft, as opposed to an art or a science (perhaps a controversial view, but for the sake of argument), than language is simply a crafters tools. Consider two carpenters attempting to build an intricate piece of furniture; the first owns only a hammer and the second an entire warehouse with thousands of tools each of its own specific task. Abraham Maslow described exactly what might happen in the first situation within his 1966 publication, The Psychology of Science; “if all you have is a hammer, everything looks like a nail”. In short, because his tools aren’t appropriate for the job, you can expect a crude solution, tortured into working properly. On the other hand, the second carpenter is sure to have either forgotten how to use his tools properly, mixed up appropriate tools or died of fatigue in search of his tools and their documentation. Programming languages must focus both on the quality and the quantity of their features and specifications. As Dijkstra states later in The Humble Programmer, “the tools we are trying to use and the language or notation we are using to express or record our thoughts arc the major factors determining what we can think or express at all”. Similarly, the quality of our languages affects the quality of our software, too many features, abstractions, structures, et cetera truly are unmanageable both for computer systems and their programmers.
“[L]esson[s] we should have learned from the recent past”
Dijkstra’s statement in The Humble Programmer shows that he believed that a ballooning of language complexity was already beginning to occur. Relative to modern languages it’s easy to scoff at Dijkstra’s outlook, this was of course prior to the internet and technological revolution. But in retrospect, this statement may have occurred at right about the time that language complexities were starting to spiral out of control. Remember, this ACM conference was occurring less than two decades after the release of the first compiler, FORTRAN, LISP, ALGOL 58, COBOL, and less than a decade after the release of Simula, Speakeasy, BASIC, B, and Pascal. In the late 60’s and early 70’s programming languages and paradigms started to flower. Object-Oriented programming began to be developed in Speakeasy and Simula, the general-purpose imperative language C was about to be released, Prolog introduced the first logic programming language and ML built a polymorphic type system. And while these are all significant advances in the Computer Science field, they introduced new problems.
Initially almost any update of a language was unequivocally considered an improvement, however specifications for new languages were becoming too complex for developers, and compilers were wrought with bugs. Many of these languages released faulty updates in an attempt to create more productive languages within their domain. COBOL’s gravitation towards human-readability for businesses led many programmers to migrate back to symbol based languages, and Lisps introduction of the first garbage-collector, as well as functional and procedural paradigms felt cumbersome for its time. Language designers were being heralded as the messiahs of computer science, and their over-confidence led to the creation of tools, features and specifications that simply couldn’t be intuitively built or maintained. I’m inclined to believe that Dijkstra was being purposefully exaggerative within his quote, in an attempt to scare the programming world into avoiding building bad languages that would inevitably be the foundation for bad software.
“‘richer’ or ‘more powerful’ [contemporary] programming languages”
Unfortunately the momentum of software complexity has continued to build to this day. While a mere 3.6 MB of code brought the Apollo 11 to the moon 1 (which is now publicly available on GitHub courtesy of Chris Garry), the newest Mac operating system was nearly 15 GB in size. Where legacy software often resembled a perfectly assembled jigsaw puzzle, modern software is akin to taking a piece from multiple puzzles and forcing them together. The multitude and complexity of programming languages, their features, libraries, and lack of maintenance and documentation has exacerbated this problem. Consider the timeline of the C-Family of programming languages. Initially called BCPL, it was introduced in 1966 as a procedural, imperative, and structured computer programming language with constructs that mapped efficiently to typical machine instructions. BCPL evolved into B which introduced recursion, machine independence and non-numeric data, then updated and rereleased in 1969 as C. As described earlier these changes were (for the most part) unequivocally were considered improvements. However the same cannot be said for the changes to C since then. While C itself has only undergone modest changes (thank goodness), it has since branched into a plethora of derivatives such as; Ratfor, AWK, C++, AMPL, PROMAL, Objective-C, C*, Perl, Telescript, Java, S-Lang, Oak, Split-C, Agora, Amiga E, R, SAC, Pike Cilk, Claire, Alef, Limbo, PHP, LPC, Handel-C, Charm, C—, CINT, C#, Ch, D, Cyclone, Falcon, Nemerle, eC, Neko, BitC, NCS, GO, Lite-C, OpenCL, Noop, Axum, Dart, S. AHHHHHHHH. Thankfully, for the sake of your time and my own, we’ll simply look at the complexity of one of C’s most popular derivates; C++.
C++ is one of the richest programming languages currently available, it has almost any control structure, data structure, operator and feature available in some way or another to the user. Advocates of the language believe this is a feature, that users should understand each feature they are using prior to using it. I have two counterpoints to this; 1) There are many things a programmer doesn’t know they don’t know, they can’t understand something if they don’t know there is something to understand. 2) The language itself is still too vast to understand all of the features and complexities that it holds. Bjarne Stroupstrup, the creator and developer of C++ has said himself “Even I can’t answer every question about C++ without reference to supporting material (e.g. my own books, online documentation, or the standard). I’m sure that if I tried to keep all of that information in my head, I’d become a worse programmer. What I do have is a far less detailed – arguably higher level – model of C++ in my head”2. This is the most notable reason to the slow phasing out of C++; it’s complexities are unsafe for the unaware and unproductive for the rest of us.
In 1972 Edsger Dijkstra commented on the detrimental nature of unmanageable and complex ‘rich’ programming languages within his ACM presentation The Humble Programmer. His observations were sound in the seventies, however, the momentum of language complexity has yet to falter. The breadth and multitude of languages, documentation, and features available today only reinforces Dijkstra’s fears. Rich and General-purpose languages such as C++ and Java have started to balloon to an unmanageable size. If we aren’t able to realize Dijkstra’s vision of simple and manageable language development, we will be building a foundation for unmanageable software systems in the future and consequently contributing to the software crisis (which will inevitably collapse with size). As similar as Computer Science is to carpentry, people tend to be more courteous of the learning how to operate a dangerous power tool than they do of operating a dangerous language. Perhaps if the flaws in our languages cut off limbs, we would finally be truly critical of the languages that construct our digital systems.