TCEA Area IV '97 Slides


Choice of Language, II:
A Language Comparison

Let us contrast a program written in Scheme with one written in C. Here is the Scheme equivalent of the program we developed earlier. Note that the only real difference is that the parentheses are placed a little differently, and the commas have been removed:

(define (in-list? i sl)
  (if (empty? sl)
      false
      (if (equal? i (first sl))
          true
          (in-list? i (rest sl)))))
This program can be tested immediately with a few examples (again notice how similar these look to the examples we wrote before):
(in-list? "cheese" empty)

(in-list? "cheese" (put "cheese" empty))

(in-list? "cheese" (put "apples" (put "cheese" empty)))

(in-list? "cake" (put "apples" (put "cheese" empty)))
When these are entered into the Scheme environment, it responds with true or false, as appropriate.

In contrast, here is the same program in C. The portions highlighted in red are the parts which add no intellectual value to the program; they are merely artifacts of C's technology which must be explained before the student can write this program.

#include <stdio.h>

typedef struct shoppingListElement *  shoppingList;

typedef char * shoppingItem;

typedef struct shoppingListElement {
  shoppingItem item;
  shoppingItem rest;
}

int in_list (shoppingItem i, shoppingList sl) {
  if (NULL == sl)
    return 0;
  else if (i == (sl -> item))
    return 1;
  else
    return (in_list (i, sl -> rest));
}
There are more complications. The portions in purple (==) require special care; using = instead will make the program produce wildly different output. (This trap is sprung even on professional C programmers with annoying regularity.) Finally, the orange portions (->), which are pointer dereferences, hide a nasty truth: C does not check whether the pointer is valid and, even if it is, whether there is in fact such a field in the object pointed to. If there is an error, the system may never signal it, instead letting the program run for millions of instructions, often to produce an answer (which, insidiously, may be close enough to the right answer that the programmer may never know the program is wrong, only to have it crash on a later run).

But this is only half the problem! Even after writing this code, the student is nowhere near testing it. That requires another block of code:


void main ()
{
  shoppingItem  i1 = "cheese";
  shoppingItem  i2 = "coke";
  shoppingList  l0, l1, l2;

  l0 = NULL;

  l1 = (shoppingList) malloc (sizeof (shoppingList));
  l1 -> item = "cheese";
  l1 -> rest = l0;

  l2 = (shoppingList) malloc (sizeof (shoppingList));
  l2 -> item = "apples";
  l2 -> rest = l1;

  printf ("%d\n", in_list (i1, l0));
  printf ("%d\n", in_list (i1, l1));
  printf ("%d\n", in_list (i1, l2));
  printf ("%d\n", in_list (i2, l2));

  exit (0);
}

The student has to write all this code just to test out the function. This code is fraught with even more difficulties, including the need to understand the malloc procedure, casts, and formatted output. In DrScheme, one more test case means just typing the function application in the Interactions window. In C, it means editing this program, adding the proper declarations and compiling it before it can be run.

(Actually, this program has some minor and some major errors, but many compilers don't flag them, and on most systems it produces the right answers. Teachers who use C or C++ may wish to find these errors.)

PLT / scheme@cs.rice.edu

Last modified at 10:49:37 CST on Monday, November 10, 1997