Journal Articles

CVu Journal Vol 11, #4 - Jun 1999
Browse in : All > Journals > CVu > 114 (20)

Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.

Title: Learning to Program

Author: Administrator

Date: 03 June 1999 13:15:31 +01:00 or Thu, 03 June 1999 13:15:31 +01:00

Summary: 

Body: 

A question that I am often asked is 'Should I first learn C?' An increasingly frequent alternative these days is 'Should I first learn Java?' Note those uses of the word 'first' with the implication that what you ultimately want to learn is something else.

Let me assume that what the questioner really wants is to learn to program. Perhaps the question should be 'What is a good first language to learn?' I could try to answer that question but I am pretty sure that whatever answer I came up with would cause howls of anguish from some of you. Perhaps a better question is 'How should I learn to program?'

If you asked me that question I would ask you why you wanted to program. Then I would ask you what you are interested in and whether you had any thoughts as to how programming might help you with those interests. As far as I am concerned learning to program should be enjoyable and in some way enrich your life. I only once attended a course aimed at teaching me to program.

Some time in the distant past I enrolled in a two-term course on FORTRAN 4. The course leader was a fanatical campanologist (a hobby so arcane that Microsoft's spell checker has never heard of it) an could think of nothing more exhilarating than writing a program which would tell you how to ring the changes on the bells at your local church (just to thoroughly annoy all the locals trying to enjoy a pleasant summer weekend). However knowledgeable a teacher he might have been he made the classic mistake of imposing his interests on his class. Fortunately I had no need of a certificate of successful completion of the course because I had better things to do with my time than write silly programs about things that left me completely stupefied.

Of course we must choose achievable objectives, so the gardening enthusiast better not set out to develop a garden design program as their first program. However fairly early on they might try writing a program that would identify potential problems with their garden. Some plants do not do well in the presence of some others, some do particularly well together (for example planting garlic in your rose-bed will greatly enhance the scent of your roses, planting carrots near onions will mutually protect both from one of their parasites.). The keen gardener could work at a program that might eventually become a bit more than a toy.

Whatever your interest it is possible to find simple programs that feed of it. Of course we must be realistic and not expect that our early programs will have any great use other than letting us learn to program while doing things that interest us. I too often see one of two mistakes made in books and courses aimed at novices: the author/instructor wants to define a domain that s/he is familiar with or the student expects their first efforts to be of great use.

Rule 1 in my opinion is that programming exercise should be meaningful to the student.

The next important issue is that the student must get reasonably quick success based on a small subset of the language being used. The crazy presenter of the FORTRAN course failed here as well. He wanted all our input to be in free format. In other words almost from word go we had to input strings and parse them ourselves. OK so he could do it and there would be times when we might need to, but that is not the place to start. Too many students will fail to get their first program working reasonably quickly (and these were times when most course members were getting a seven day turn round).

Rule 2 is that students should quickly produce correct working programs.

Note that qualification, working is not enough they must also be correct. Look at the following piece of code and tell me what is wrong:

#include <stdio.h>
main(){
  char name[30];
  printf("What is your name: ");
  scanf("%s", name);
  printf("%s\n", name);
  return 0;
}

This is a typical kind of tiny program that is used as an exercise in far too many books purporting to teach you to program (in C). The problem is that it is riddled with magic (things that have to be done just right even if you do not understand why) and dangerous coding practice. Note that if C is the language you choose to learn to program in, even such a simple thing as this program requires that you use a wide range of language features. What is worse is that bad habits are already creeping in. We have a magic number (the number of characters in the array), inappropriate use of library functions (puts() would be better than printf() in this case. Incorrect use of a format specifier (it should have been %29s to protect the end of the array). Now try to explain the relationship between the correct specifier and the actual size of the array. Worse still, try to explain to the novice why you have to place a literal (29) in the specifier and cannot, in any simple way, get it calculated from the array size. The poor novice simply has to learn too many things to get even a simple program to work correctly and safely.

This is why C is not a very good language in which to start learning to program. By the way, very similar objections can be raised when considering Pascal as a first language. Indeed this start-up cost is a serious problem with most languages. Some like Pascal frustrate the novice by repeatedly rejecting code because it does not meet the pedantic requirements of the language. Others like Smalltalk and Lisp require eccentric views of the World that do not comfortably meet our normal ways of thought. This same problem applies to the language I used as a school-teacher: Forth. The one advantage that Forth gave me was the ability to provide extra facilities for my students. For example, I had complete support for 'Turtle Graphics' as originally developed by Seymour Papert. This meant that from a very early stage my students could get dramatic results from comparatively small amounts of code. Getting a lot for a little motivates people to discover how much more they can get from learning more. None-the-less both Forth (enhanced for use in the classroom) and LOGO make considerable demands on the pupils understanding (which can only be catered for my teachers who know what they are doing and understand what the pupil is trying to ask).

You could aim the same complaints at C++ (and in my opinion you can when you consider Java - there is too much complexity in writing your first programs, things are frequently counter-intuitive). Before I look further at C++ as a first language let me mention scripting languages. Certainly some of these are well worth consideration. Languages like Javascript, Python and AWK can deliver a great deal for very little as long as your point of interest is close to the domain for which the scripting language was designed.

Now when we start any language novices will need to accept that there are certain things that the system (IDE or whatever) will need in order to get out the right functionality. I have never had any problem with introducing the purpose of a header file. As I always teach my students to write their own header files from very early on they soon get an explanation of what header files are for. There is nothing better than doing for yourself in order to gain insight into things that have been done for you. One of my main bones of contention with many (most) books and courses is that they avoid getting students writing header files.

For me, the main criteria for learning to program is a language and programming environment that:

  1. Provides good abstractions that map cleanly onto language facilities.

  2. The ability to write correct code after learning very little

  3. A good development path

  4. The ability to work in a number of different ways (or paradigms)

Most currently available languages fail on at least one of the above criteria. Indeed most fail criterion (1) and many of the popular ones fail criterion (4). For me Java has a deep flaw in that its type system (built-in versus user-defined) requires an early awareness of the distinction between attribute (or value) types and object types. Java is a form of C with some of the more dangerous (in the hands of novices) features removed. However it has a superficial simplicity that masks some tough concepts that have to be grasped early on if any progress is to be made. One of the most irritating features of Java is its invasive form of exception handling. All but the simplest programs require the programmer to contribute something. These frequently results in the user code being encapsulated in a try block with the subsequent catch blocks actually doing nothing. The language can enforce the catch, but it can do nothing to ensure that the programmer actually processes. The result is that there is reams of code being written which only superficially meets the requirements. Think what that is teaching aspiring programmers.

Languages like Smalltalk with a dedicated OO view of the World result in aspiring programmers coming to think that the World must be forced into a bizarre mould. Almost everyone has a concept of an attribute, which makes a language that does not cleanly support such a concept alien to our thinking.

Other languages such as Eiffel have too much necessary infrastructure to make them good starting points.

I have no problem with most of these languages learned by experienced programmers for use in a particular application domain. Where I have a problem is in using them for introducing the general concepts of programming. Of course a good teacher can make use of the tools available but the poorer the fit between what s/he intends to achieve and the tool being used the harder the job will be.

Using C++ for Learning

Before I get to deeply into this last and possibly contentious part of this article, let me invite all of you to contribute articles for future issues outlining how you would use the language of your choice to teach novices to program.

I believe there is a way to use C++ for teaching programming concepts. Certainly modern C++ meets the last of my criteria. Those that understand what the language can do will find that it also meets the other three.

Modern C++ has added one extra piece of magic that must be explained, that is the using directive (probably the better way for the absolute beginner) to open up the standard library features. So typically someone being introduced to programming via C++ needs to be provided the following magic incantations:

#include <iostream>
#include <string>
using namespace std;

Even the incantations are pretty transparent: include input/output facilities, include string facilities and make the standard library available. Of course later on you will want to go into more detail, but at this stage you do not even have to tackle the concept of a header file (and note that there is no requirement even in C that a standard header even be a file, and certainly the standard header names are not even legitimate file names on some systems).

Next you need to introduce the concept of an entry point and a return value. It really isn't too hard for anyone who is going to make even simple use of programming to grasp the idea that you need some way to return information from a program or function. So we get the next line:

int main() {

If you have difficulty explaining this much you probably should not be teaching or writing about programming. If you have a problem with understanding it you might be better off acquiring some quite different skills. Of course, up till now we have had the same kind of problems that we would have had if we were introducing C, and just as much when introducing Java (not the same magic incantations but none-the-less we need to worry about things like file names etc.)

Those who will insist on introducing C++ as a 'better C' will still not get any benefit but look at the rest of the C++ code to do the same thing as my earlier C program:

  string name;
  cout << "What is your name? ";
  cin >> name;
  cout << name << endl;
  return 0;
}

The big advantage is that this program not only works but does so correctly. There are no magic numbers, no weird explanations about arrays and how array names decay into pointers, and why the input routine needs a pointer etc. I will avoid the claim that the code is self-explanatory, we do need to explain to the novice that cout and cin are a sink and a source of data. We do need to explain the use of the insertion and extraction operator etc. However each explanation at this stage is self-supporting. For example, if you want a string, declare one, if you want to end a line, say so etc. The time to get into complexities is later after the novice has written some working code. I certainly find it easier to explain the use of cout and cin instead of printf and scanf. Please note that most authors never even mention that you can prevent over-writing the end of an array of char in C by selecting the correct form of the format specifier for a string. That does not say much for their understanding of either C or the needs of novice readers.

The program may not do much, but then we have not had to learn very much to write it and have some high level understanding of how it works. In other words the payback is reasonable for the effort put in.

Now let me move on to another very elementary programming exercise.

Problem:

Write a program that asks for your name, age and salary (as a whole number of US dollars) and then classifies your salary as poor if it is less than your age times 500, good if it is greater than 1000 times your age and average otherwise. It must output:

<name>'s salary of $<amount> is <poor, average or good>

A Solution:

#include <iostream>
#include <string>
using namespace std;
int main(){
  cout  >> "What is your name please?  ";
  string name;
  cin >> name;
  cout >> "How old are you (whole number of years)? ";
  int age;
  cin >> age;
  cout >> "What is your annual salary (in dollars)? ";
  int salary;
  cin >> salary;
  cout << name << "'s salary of  $"<< salary << " is ";
  if (salary < (age * 500)) cout << "poor";
  else if (salary > (age * 1000)) cout << "good";
  else cout << "average";
  cout << "." << endl;
  return 0;
}

Of course this code needs refinement. The input needs validation and potential white-space characters in names needs to be dealt with. There are stylistic issues such as the layout of the if statements and where to deal with the full stop that ends the final output. Each of these points is a valid teaching point in itself and each one is comprehensible to anyone with the intellectual equipment to learn to program. Nowhere do we have to fiddle with low level language features.

By the way, I know that the language allows me to omit that return statement but doing so only leads to unnecessary complexity when discussing the form of the main() statement. Once your novice is comfortable with return statements you can add that C++ makes a main a special case and allows the return to be left out.

During the process of the first few hours of programming the novice can repeatedly return to this problem and progressively improve the code. Because the code maps well to the problem it is easy to maintain and refine.

As a teacher I would very soon introduce the idea of a function to capture and validate an int input. Something like:

void get_int(string const & prompt, int & value, int minValue, int maxValue);

Initially I would provide an implementation of this as object code, with a header file containing all the relevant prototypes for the functions I was providing. Then the student could write:

#include <iostream>
#include <string>
using namespace std;
int main(){
  string name;
  get_string_data ("What is your name please?  ", name);
  int age;
  get_int( "How old are you (whole number of years)? ", age, 5, 100);
  int salary;
  get_int( "What is your annual salary (in dollars)? ", salary, 0, 1000000);
  output_report(name, age, salary);
  return 0;
}

And again we have a pile of teaching points that come directly from this code. This probably the time to deal with the issue of magic numbers.

My main theme is that language learning should be problem driven. New aspects of the language are introduced to meet problems that need a solution. At some stage I would raise the issue of how to move the program into French, German etc. C++ supports many standard high level abstractions (containers, algorithms etc.) and provides the tools so that the teacher/writer can add other abstractions to support the needs of the newcomer. Of course, at some stage I am going to ask my students to write their own versions of the functions that I have provided as object code. That will also carry a message, abstractions can have many implementations.

If you have studied my code above you will realise that I am passing name, age and salary by reference. Now those of you who cut your teeth on C are probably horrified, while those of you who are efficiency fanatics are worrying yourselves silly as to the relative benefits of passing by reference versus passing a pointer. My advice to both groups is 'Stop it.' Those are exactly the kind of idiocies that confuse novices. C programmers effectively pass arrays by reference (though the mechanism is subject to some real dangers - you cannot distinguish between an array and the address of a single instance), so why do they get so strung out by passing other types that way? If there is any difference in efficiency it is minuscule. I would be quite happy to stick with passing by reference for the first few hours of any course (something that C++ allows while C does not).

C++, like English, has great complexity available. However it is not required that you use that complexity until you need it. Novice code, like application code, should be essentially simple with simple relationships between the concepts (abstractions) and the code.

I think that is enough from me. I hope that at least one of you will propose and defend the use of some other language for introducing novices to programming. I will happily publish articles on the subject, and not confine the choice to C related languages. However whatever language you choose, it needs to be widely available on common machines at a reasonable price. So if you propose a language (other than C, C++ and Java) I expect you to list sources of compilers/interpreters for Wintel, Linux and Apple Macs at the very least.

Notes: 

More fields may be available via dynamicdata ..