The Various (Wrong) Approaches to Introductory Programming Languages

Linda McIver’s Thesis Approach
The “Structure and Interpretation of Computer Programs” Approach
The “Teach in C” Approach
The “First Programming Language Should Make Sure You Write Good Code” Fallacy
The “It Should Have a Decent IDE” Fallacy

Linda McIver’s Thesis Approach

Linda McIver published along with Damian Conway a paper titled “Seven Deadly Sins of Introductory Programming Language Design” that explains the problems they found with most popular introductory programming languages. The article makes a very good read.

Later on, her Ph.D. thesis introduced her idea of a good introductory programming language.

Now, if I had to summarise this language in one word it would be this: sexless. It’s incredibly limited, not flexible, and not fun. It has no pointers or references and instead relies on nested structures and arrays. There are two basic data types - a number and a string. The language does not have functions as first-order objects, closures, or objects and classes in the Object Oriented Programming sense. Furthermore, it has very few ways for one to express oneself. As a result implementing many algorithms would be very difficult in it.

When I program, I’m using every tool in my arsenal, and expect the language to be powerful enough to be able to translate my thoughts into code. McIver’s language is too limited and limiting, to be effective for programming in, and being planned exclusively for beginners, lacks the richness and interesting idioms that make programmers like or even love their languages.

This is a language that I won’t enjoy programming in. And I don’t believe a professor who doesn’t enjoy programming in a certain language can effectively convey it to his students, while lacking the enthusiasm and love for the tool he chose.

McIver’s approach is flawed in the sense that she is trying too hard to save the students from all possible problems they may encounter in trying to understand their introductory language. However, programming is hard to learn, and learning the first language is always difficult. Creating a “flawless” language that lacks any sex-appeal is not going to make it better, but much worse as both the professors and programmers will detest it.

The “Structure and Interpretation of Computer Programs” Approach

“Structure and Interpretation of Computer Programs” (or SICP for short) is a classic text and course material on programming, taught at MIT and many other universities around the world. SICP uses Scheme (a minimalistic dialect of Lisp) as its exclusive language to cover many important programming and meta-programming concepts.

I have read the book in my third semester of the Technion (without doing the exercises) and later took both of the SICP courses that were given by my department. I learned a lot from the book, and while the courses did not teach me too much new, I did enjoy working on the exercises.

However, there are several problems with teaching Scheme as an introductory language. The first is that it is too impractical. Scheme does not have system primitives that more modern languages take for granted like ones for random file and directory I/O, sockets, graphics primitives, Graphical User Interface (GUI), etc. Moreover, the core language is limited and most practical code tends to become very verbose in it. For example, whereas in Perl one would write $myarray[$i]++ to increment an array element by one, in Scheme it would be: (vector-set! myarray i (1+ (vector-ref myarray i))).

Most of the SICP exercises are about number theory, recursion, and a lot of other relatively abstract stuff, and too few are about real world and exciting tasks: writing games and other demos, working with files, writing scripts and utilities, networking and working with the WWW, etc. In fact, the Scheme standards define too few useful things. Most of the dazzling number of different Scheme implementations all extend the language in several ways, but all have their own idea of how to do it. Compare it to Perl, Python and friends which have one main C-based implementation, or to C where the standard library is actually quite useful.

I believe an introductory language has to grow with you. When I studied BASIC, I was able to use it for programming games, graphical demonstrations and animations, scripts, and other uses. I continued to use BASIC on DOS and Windows, until I learned the much-superior Perl, which I’m using today.

The “Teach in C” Approach

In his “Back to Basics” essay, Joel Spolsky gave a case for teaching ANSI C as an introductory language instead of more high level languages. His argument is that programmers will end up writing sub-optimal code because some low-level elements of dealing with strings and arrays are abstracted away in higher-level language.

ANSI C and C++ have been popular introductory languages for teaching programming for many years now. While some schools have switched to teaching Java or a different language, C and C++ are still very popular.

However, C has one major deficiency: it’s too close to the processor to be useful. In order to perform an operation on two objects, one should allocate them first, perform the operation, and then take care of freeing both objects and the result (to say nothing of edge cases where allocating or freeing may fail.).

All this work to do something that in high level, garbage collected, languages is as simple as $result = $object1 OP $object2;. From my experience with Technion students, they are often get so bogged up in the technicalities of working with C instead of getting quick, dirty and useful code running.

A good introductory programming language should allow you to write a lot of useful code quickly, and not slow you down with many low-level constraints. Beginning programmers have a hard enough time learning how to translate their thoughts and intentions into working code, and solving bugs and the last thing they need is to deal with too many idiosyncrasies of the language only because it is too low-level.

Spolsky’s argument about the efficiency of some operations is wrong, because programmers who learn such languages won’t often notice the difference from such inefficient operations, due to the incredible speed of contemporary computers and the fact that their data sets are generally too small. Moreover, many instructors and exercise checkers won’t penalise for the presence of such issues in their homework.

While the efficiency of algorithms and the underlying implementation of language primitives should be stressed at a certain point, the first task of an introductory course is to make sure a programmer can learn to write code, not necessarily the most efficient one. (Not even according to asymptotic complexity). Learning how to write quick and dirty code is a mental leap that is large enough as it is.

The “First Programming Language Should Make Sure You Write Good Code” Fallacy

You many times hear people saying that beginning programmers should be taught using a programming language that restricts them and forces them to write good code. Languages like Pascal, Ada, Java, and many others were designed to try to save programmers from themselves. And indeed many people believe that programmers should start learning from such a language.

What’s wrong with this approach? Several things:

  • The more strict the language is, then generally the less expressive it is. Programmers like to express themselves and be able to implement algorithms using the entire power of the language. They don’t want to declare a lot of type definitions, many constraints, write a lot of syntax, or otherwise be encumbered in the way.

    It may actually make them think programming is loathsome or otherwise a very strict process instead of a very creative process.[haskell]

  • Often, the trial and error will be good for them. Plus, even writing some disorganised, but functional code is better than the program taking them much more time to write (and more time to read and understand after writing).

    I don’t expect them to become superb programming in a day. Becoming a better programmer is a process, and cannot be taught in a semester or a year of hard work.

The “It Should Have a Decent IDE” Fallacy

Many education institutions reject many languages as introductory languages because they don’t have a decent integrated development environment (or IDE for short). An IDE as useful and convenient as it is, however, is not an absolute requirement.

Programming does not happen in the IDE - it happens in the mind. Programmers should learn to write code that does something. By using the text editor (of the IDE or a standalone one) and writing text that does something, they can best learn to program for the real world.

There is a myth that programming using a text editor and a command line is too difficult for mortals. This is false because, as late as the 1980’s or 1990’s, almost all personal computers used a command-line interface (often a BASIC interpreter or DOS), and required programming using non-graphical editors, and it was still adequate for most people. (To say nothing of earlier interfaces such as Teleprinters (TTYs) or punched cards). Plus, it is hard for a programmer to avoid typing code entirely.

[haskell] A comment to the first revision of this article claimed that Some languages, like Haskell, derive their expressive power exactly because of the restrictions imposed. My reply is that arguably languages like Lisp have the same expressive power, but obviously a more verbose syntax due to the fact they are using S-expressions and that they are lacking some functions that were added to Haskell, O’Caml and SML. Perl 6 aims to combine more idioms from Haskell and Lisp than Perl 5 already has, yielding a language that’s generally even more succinct.

I believe that Haskell derives its expressiveness not from its strictness, but rather from its abstractions, and that this expressiveness can be duplicated to a large extent in a less strongly typed language. However, my mastery of Haskell is still somewhat superficial, and so I’m not fully qualified to comment on it.