I’ll Tell You When You’re Older

I’d like to address something that I’ll call the “I’ll tell you when you’re older” phenomenon in computer science education. This mostly has to do with programming, but there are also situations in theory education where this happens as well. Specifically here I’m going to discuss how it can affect the choice of a teaching language.

As is often the case with something so complex and with such a storied history, programming languages have quirks, gotchas, and many layers of operation. Therefore, it turns out to be extremely tempting when introducing an aspiring programmer to his or her first computer language to try as much as possible to avoid confusing the student by eliding material that isn’t relevant to the lesson at hand. Essentially, this means deflecting tangential questions, or anticipated questions, with the educational equivalent of the commonly experienced childhood situation where your parent promises to explain to you what some mature or risque term means “when you’re older.” In this sense, the instructor is requiring the student to wait until a later point in the course before explaining the meaning of a particular concept or construct.

In the abstract, this seems to be an advisable thing to do, but (though I certainly haven’t done formal study to back up this assertion) I suspect that it encourages the dreaded practice known as cargo-cult programming. Cargo-cult programming is the software engineering manifestation of an appeal to authority. It entails the use of patterns or code fragments when one does not really understand what they do or why they are being used, simply because one has been instructed to use them, or has seen an instructor silently do so.

It is my belief that a programmer, be he a student or a professional, should never, ever write a line of code without understanding what it does or why they wrote it. This maxim is fundamentally incompatible with the “I’ll tell you when you’re older” educational tactic because that tactic necessarily entails that the student use something without having understood it. So this tactic should be avoided whenever possible, and it should absolutely be avoided in a student’s very first lesson.

Now, I’m not trying to say that simplification is wrong. For example, when introducing STL containers to a student of C++, it would be sufficient to explain that vector is a container whose elements must all be of one type, and that the notation vector<string> means that this particular vector will contain string objects. This gets across the idea of exactly what the angle-bracket notation means in the context of containers, and a student can extrapolate from that with success. One need not launch into a detailed explanation of the C++ templating system in order to provide an adequate and non-evasive explanation.

The key is not so much to be exhaustive but to give the student a sense of control. When I was ten years old, I experienced an epiphany regarding computers. A friend of mine came to my house, sat at my computer, and showed me how to rearrange groups in Windows 3.1’s program manager, and how to change settings in the control panel. Before that point, I felt like I was operating in an environment that I could not control – that the rules of the system were hidden from me, and that as a consequence I had to interact with the operating system in a very specific, scripted, inflexible way. By showing me how things worked, and how they were configured, and demonstrating that the operating system was truly under my control.

From then on, I had a much easier time learning how more complicated interactions with the computer worked. The explanation gave me a foundation of knowledge to build on, rather than just a script, and the feeling of control and understanding gave me confidence to experiment. So it is also with programming. A novice programmer must be comfortable in his or her language environment in order to be an effective learner.

As I mentioned above, a particularly crucial point where a student should be told everything up front, is a first introduction to a programming language – in particular, a first introduction to a first programming language.

Here, there is a distinct difference between which language is used to teach. Consider the “boilerplate” code that a language requires — the minimum framing code that must go before, or around, any executable code that the instructor wishes to demonstrate in order to make a complete, valid program.

In some languages, this is quite minimal and easy to explain. For example, in Python (or analogously in Perl, Ruby, Bash, or almost any other interpreted language), all you need is something like

#!/usr/bin/python

Or in fact nothing at all if you use the interpreter interactively, or provide the source file as an argument to the interpreter. When the shebang line is needed, the explanation can be terse: “This line tells the computer which programming language interpreter should be used to run this program.” Though you may still need to explain the term interpreter if you have not yet already.

In C or in C++, you end up with something a bit more involved, like:

int main() 
{
  return 0;
}

The return statement is not strictly necessary but in my opinion things are more confusing without it. Here, to give the student an understanding of the boilerplate code, you must explain the concept of a function. With a simple function like this, such a thing can be done with an analogy to mathematical functions with which the student is likely familiar. The only sticking points would be giving a rationale for why a function may take no arguments (which does not happen in mathematics), and perhaps explaining the concept of side-effects lest the student take the analogy with mathematical functions too literally. This level of explanation can easily be done within the prologue to a first lesson.

But then you get to something like Java (or similarly, C#), wherein the minimal boilerplate code is the following:

public class ApplicationName 
{
  public static void main(String[] args)
  {
  }
};

Here, the requirements for fully understanding the boilerplate code balloon substantially. To fully understand this code, in addition to everything that needs to be explain in the C/C++ example, one must understand what access modifiers are, what a string is, what an array is, where the args parameter will come from, what a class and an object are, what a method is, and how a static method differs from a non-static method. This goes far beyond what one could, or would want to, explain as introductory material, and here the temptation to say, “Just write this around your code. Don’t worry about what it does, I’ll tell you when you’re older,” becomes very great indeed.

For this reason I think that Java and C# (and other purely object-oriented languages) suffer a severe handicap as first teaching languages. In order to write code in an object-oriented language and understand what it is that you are writing, one must first understand the concept of objects, which is a very difficult thing to explain without first teaching other programming concepts. This handicap applies not only to the boilerplate code, but extends into any introductory instruction, as so many language features revolve around objects. One must continue to put off the explanation of what objects are and why they are employed while still instructing the student to use and create them frequently.

These languages are nevertheless popular as starter languages because they feature automatic memory management and enforce object-oriented design. While both of these are indeed important, in my opinion they do not warrant the sacrifice of having to teach beginners that cargo-cult programming is sometimes acceptable. Besides, one can get quite far even in C++ without needing to touch manual memory management (which any serious programmer must eventually learn anyway), and object-oriented design can be taught independently of language once a sufficient familiarity with programming in general has been established.

In my opinion, an ideal teaching language is a multi-paradigm language so that instruction can begin with imperative programming, which is the simplest to explain in full, move on to procedural programming, and then finally to object-oriented programming and beyond, all without changing syntax. This allows knowledge to build, and encourages the student to comprehend what it is that he or she is writing, knowing that it will be built on later, rather than (as I discussed earlier) feeling like the program is not fully within his or her control.

Of course, there is a language that has the benefits of being multi-paradigm and memory-managed, and also has a very minimal boilerplate: Python, which I mentioned earlier. I’m curious as to why it is not more often used in formal education as an introductory language, given its excellence at being both straightforward to explain to a beginner and powerful when used by a professional. Perhaps it is a systematic bias against interpreted languages? Or maybe the faculty of Computer Science departments have all experienced one too many irritating Makefile typos and retain a vehement hatred for significant whitespace.


Share this content on:

Facebooktwittergoogle_plusredditpinterestlinkedinmailFacebooktwittergoogle_plusredditpinterestlinkedinmail

1 comment

Leave a Reply

Your email address will not be published. Required fields are marked *