You are on page 1of 8

Seven Deadly Sins of Introductory Programming Language Design

Linda M cIver & Damian Conway


Department of Computer Science
Monash University, Victoria, Australia

Abstract The observations and suggestions contained in this pa-


per have been developed as part of the GRAIL1 project
We discuss seven undesirable features common to many within the Department of Computer Science, Monash
programming languages used to teach first-time program- University. The aim of this project is to study the early ac-
mers, and illustrate typical pedagogical difficulties which quisition of programming skills, with the ultimate goal of
stem from them with examples drawn from the program- creating more usable languages and support tools.
ming languages ABC, Ada, C, C++, Eiffel, Haskell, LISP,
Modula 3, Pascal, Prolog, Scheme, and Turing. We propose Seven Deadly Sins
seven language design (or selection) principles which may
reduce the incidence of such undesirable features. 1. Less is more.

Introduction The "less is more" principle appears in many forms, al-


most all of which seem to be ultimately detrimental to the
Learning to program is difficult. We believe that a sub- learning process. Perhaps the most obvious examples are
stantial part of this difficulty arises from the structure, syn- the Scheme language and other LISP variants. Scheme has
tax and semantics of the programming languages which are effectively only one data type – the list – and one operation
commonly used to teach programming. – evaluation of a list. While this abstraction is very simple
Programming language designers are (of necessity) to explain, and not difficult for the beginner to grasp super-
highly intelligent experts in the field of programming, and ficially, it does result in code that is difficult to read because
are consequently far removed both temporally and cogni- of large numbers of nested parentheses and the absence of
tively from the difficulties experienced by the novice pro- other structuring punctuation.
grammer. This gulf of experience and ability results in lan- Furthermore, to support this extreme degree of homo-
guages which are either too restrictive or too powerful (or geneity, a large number of inbuilt functions are required,
sometimes, paradoxically, both). many of which are quite sophisticated in their behaviour,
We divide introductory programming languages into and therefore difficult to understand and use correctly (for
two broad categories: special purpose teaching languages example: sort vs sortcar in Franz LISP [14]).
(such as Pascal [1], Turing [2], ABC [3]) and popular "real- A "less is more" approach is usually justified in terms of
world" languages (such as C [4], C++ [5], Ada [6], Modula paradigmatic purity: strict adherence to a single functional,
3 [7], Haskell [8], and Scheme [9]). logical or object oriented paradigm. While this orthodoxy
There is a long history of scholarly and less-than-schol- can make for a certain conceptual simplicity and elegance
arly debate [10,11,12,13] regarding the comparative merits (which can be of considerable advantage in teaching con-
and flaws of many of these languages. Typically this debate cepts such as scoping, recursion and encapsulation), in prac-
centres on theoretical issues (such as expressiveness, range tice it can also lead to extremely obscure and unreadable
of concepts supported, or paradigmatic integrity) and code. In some cases, relatively simple programs must be
practical considerations (such as range of available plat- substantially restructured to achieve even basic effects such
forms, support tools and environments, or efficiency). This as input and output.
paper departs from that tradition in that it focuses exclu- The underlying pedagogical difficulty is that students
sively on the issues which arise in the context of teaching are not used to solving problems in a single pure paradigm.
introductory programming. Much of the problem solving they do in the real world is
We enumerate seven serious pedagogical problems, procedural in nature (cooking a meal, totalling a restaurant
each of which is common to most or all of the above-men- bill, etc.), but other problems with which they are familiar
tioned languages, even those specifically designed for are more amenable to constraint solving (dispute resolution,
teaching. We also propose a like number of design princi- holiday planning, budgeting), a functional or pipe-line ap-
ples, which we believe will lead to the development of sig- proach (collaborative tasks, various types of component as-
nificantly more "teachable" introductory programming lan- sembly), or even object-oriented methods (using an auto-
guages. Finally we suggest seven criteria which educators matic teller machine, learning physical skills).
may find useful in evaluating existing languages for intro- The results of enforcing paradigmatic purity can be as
ductory teaching. simple as the annoying requirement in Turing that functions
have no side-effects, or as far reaching as the mysteries of
1 Genuinely Readable And Intuitive Languages
I/O in Haskell, which sometimes necessitate the warping of these constructs arise from the constraints of the ASCII
the entire structure of an otherwise elegant and comprehen- character set, whilst others are the result of a deliberate but
sible functional program. (in our view) misguided "less-is-more" design policy. The
common feature of these problems is that they are analo-
2. More is more. gous to certain sophisticated grammatical constructs in nat-
ural languages, and result in the same types of learning
It is equally true that many languages are based on de- problems as are seen in natural language acquisition.
sign philosophies which err in the other extreme. Powerful, One such construct is the syntactic synonym, in which
real world languages (C++ and Ada, for example) are two or more syntaxes are available to specify a single con-
amongst the prime culprits here. Often such languages are struct. An common example of this is dynamic array access
taught by subsetting – teaching a small but usable part of in C, wherein the second2 element of an array may be ac-
the language whilst ignoring its more powerful features. cessed by any of the following syntaxes, some of which are
At first glance this approach seems quite reasonable, but legal only in certain contexts:
two pedagogical problems frequently sabotage it. The first array[1] *(array+1) 1[array] *++array
is that textbooks and other reference materials rarely con- A less well-known example is list construction. In
fine themselves to the selected subset. The second is that, Haskell the list construction expression [1,2,3] is syn-
even if the textbook does limit itself to the required subset, onymous with 1:(2:(3:[])). In Prolog [1,2,3] is
the compiler almost certainly does not. The result is often equivalent to .(1,.(2,.(3,[]))) and both produce a
worse than if the complete language was taught: students third form on evaluation: (1,2,3).
must still contend with the full semantics of the language, In themselves, synonyms are minor irritants (which
but much of it has deliberately not been explained to them! multiply the learning curve for particular constructs by no
C++ is certainly one of the most popular languages in more than 200–300%) However, they can also have a more
"real-world" use and (for that very reason) is also increas- serious and insidious effect by blurring the underlying pro-
ingly widely taught as an introductory language. One of the gramming concept in the student's mind, because that con-
justifications typically cited for teaching C++ [11] is the cept is no longer associated with a single clear syntax.
range of low- and high-level features it provides (from bit Syntactic homonyms (constructs which are syntactically
manipulation of raw pointers, to templated abstract classes the same, but which have two or more different semantics
with polymorphic member functions). depending on context) are perhaps a more serious flaw in a
Beginners, however, are notoriously poor at maintaining language. An extreme example of this3 may be seen in the
two or more conceptual perspectives simultaneously [15]. pedagogically-oriented language Turing, in which the con-
Dichotomies of perspective (such as syntax vs semantics, struct A(B) has five distinct meanings:
static vs dynamic structure, process vs data) complicate the • call function A and pass parameter B
teaching of any programming language. The availability of • dereference the pointer B to access an object in collec-
very low-level implementation-oriented constructs and tion A
high-level solution-oriented features in a single language • access the Bth element of array A
only serves to increase substantially the already consider- • construct a set of type A with a single element having
able cognitive demands placed on the student. the value of B
As well as the obvious concerns regarding learning • create a one-letter substring of the string A consisting
curves, confusion of levels, and the difficulties of adequate of its Bth character
error detection, a wide range of features necessitates a The student, armed with only a fuzzy understanding of
commensurately complex syntax and often also entails a the differences between these concepts, finds no support
host of implicit operations and function calls, automatic from the syntax. It should be noted that the decision to over-
conversions, type inferences, and resolutions of overloaded load this construct was taken quite deliberately and on peda-
functions, variable and function scoping. gogical grounds:
Examples of this "creeping featuritis" are easy to cite:
C++ provides over 50 distinct operators at 17 levels of "Notice that referencing an element of array a with
precedence, Ada9X has 68 reserved words and over 50 pre- subscript i as in a(i) is notationally equivalent to
defined attributes, Modula 3 reserves over 100 keywords, [the pointer dereference] c(p). This is an example
and some commonly-used LISP dialects ([14] for example) of uniform referents, which means that analogous
define over 500 special functions. Because most textbooks ways of accessing data should be notationally
and compilers attempt to cover the full language, novice equivalent." [17]
programmers are forced to contend with all of these fea- Another difficult grammatical construct which fre-
tures, even if they are not using them. quently appears in languages is elision (the omission of a
syntactic component). C is well known for its default inte-
3. Grammatical traps. ger return value and its curious string literal concatenation

Another class of pedagogical problems stems from vari- 2 The fact that array[1] refers to the second element of array is itself a
grammatical trap.
ous kinds of confusing syntactic and semantic constructs 3 But not as extreme as LISP and its variants, which could be viewed as
which are present in most introductory languages. Some of one massive homonym.
behaviour, but default behaviours occur in many languages: their ancestors), nonetheless languages which attempt a
automated sorting of lists in ABC, type inference in Haskell significant degree of historical consistency inevitably per-
and Turing, LISP superbrackets, switch fall-through in petuate some problematical constructs.
C++, etc. Language designers occasionally acknowledge the prob-
lems that their quest for genetic compatibility produces:
4. Hardware dependence. "At this point, the reader may be confused at having
so many ways to define a [Haskell] function! The
In addition to battling the various syntactic and semantic decision to provide these mechanisms partly reflects
levels of an introductory language, the novice programmer historical conventions, and partly reflects the desire
is often forced to contend simultaneously with the con- for consistency (for example, in the treatment of
straints of the underlying hardware (sometimes merely for infix vs. regular functions)." [8]
the convenience of the compiler writer).
"Over the years, C++'s greatest strength and its
This "closeness to the metal" is particularly noticeable
greatest weakness has been its C compatibility. This
in the design and implementation of basic numerical and
came as no surprise." [16]
character string types. There seems no convincing reason
why the novice student, already struggling to master the As well as introducing (or compounding) the problems
syntax and semantics of various constructs, should also be inherent in a "more-is-more" approach, the addition of new
forced to deal with the details of representational precision, concepts to an old language often leads to inconsistency of
varying machine word sizes, awkward memory models, or a abstraction (consider the differing semantics of TEXT and
profusion of conceptually-equivalent but semantically-dis- other array types in Modula 3), the creation of synonyms or
tinct data types. homonyms (array indexing, function calls and pointer
The semantics of arrays in Pascal, in which the novice dereference in Turing), as well as the perpetuation of out-
must grapple with the fundamental type difference of arrays moded or flawed constructs (such as char* strings in C++)
of different lengths, is a notable example. The presence of or syntax (for example, the inexplicably-named5 car and
thirty-two distinct numerical data types in C/C++4 is an- cdr which Scheme inherits from LISP).
other. These types are particularly problematical in C as Not all syntactic or semantic inheritance stems from de-
they are generally not portable. The standard int type, for liberate decisions regarding backwards compatibility. Some
example, varies from 16 to 32 bit representations depending constructs and symbols seem to propagate memetically
on the machine and the implementation. This can lead to across language family boundaries, and have become de
strange and unexpected errors when overflow occurs. A facto standards within the programming community. This is
student whose program attempts to add a $4,000 bonus to a often despite the fact that such constructs may have been
$30,000 salary may be justifiably confused to find that the viewed by their progenitors as ad hoc and may indeed have
result is a negative number. no discernible connection with the concepts they are in-
tended to represent. Memetic compatibility is surprisingly
5. Backwards Compatibility. pervasive and may be seen in the widespread use of "stan-
dard" symbols such as * for multiplication, = or := for as-
Backwards compatibility is a useful property from the signment, array[index] for indexing.
experienced programmer's point of view, as it promotes The major pedagogical problem with the presence of
reuse of both code and programming skills. The novice such syntactic memes is that they significantly reduce the
however can take no advantage of these benefits and must degree to which the novice, an outsider to the programmer
instead bear the pedagogical costs they entail. culture, can rely on existing knowledge (such as × mean-
Backwards compatibility comes in two major forms: ing multiply, or a subscript representing an index).
"genetic" and "memetic". Whilst both forms can lead to Unfortunately, memetic compatibilities can also be par-
pedagogically suspect decisions during the design of a lan- ticularly difficult to identify (and their pedagogical effects
guage, genetic compatibility is generally the result of a con- correspondingly hard to analyse), precisely because both the
scious decision on the part of the language designers, language designer and the programming teacher are so
whereas memetic compatibility is frequently inadvertent. familiar with them.
Genetic compatibility is exemplified by the relationship
between languages such as C++ and C [16], Scheme and 6. Excessive Cleverness.
LISP [9], and Turing, Euclid and Pascal[17] , and results
from the decision to retain the semantics and often the Instances of "excessive" cleverness can be difficult to
general syntactic "look-and-feel" of an ancestor language. spot, precisely because the "excess" exists only relative to
Genetic compatibility need not of course imply the near the knowledge level of the novice. Frequently the only way
complete backwards compatibility as seen in the C/C++ re- to detect excessive cleverness is to see a novice program-
lationship (Turing and Scheme differ significantly from mer's complete misunderstanding of an "obvious" concept.

4 int, short, long, unsigned int, unsigned short, unsigned 5 "Inexplicable" in the sense that explaining that they derive from
long, float and double; plus three const and/or volatile "contents of address register" and "contents of decrement register"
variants of each. respectively, rarely assists the student's comprehension or recall.
The premier example of the adverse effects of clever- designer can commit. Some examples are very well-known,
ness in programming language design (and one which is such as the almost maliciously designed C/C++:
obvious to programmers at all skill levels) must surely be if (x=0 || -10<y<10) { /* WHATEVER */ }
the C/C++ declaration syntax [10]. On the surface, it seems in which the condition always evaluates to true (regardless
like an excellent notion: let declarations mirror usage. of the values of x and y) whilst the value of x is silently re-
Unfortunately, the very concept undermines the principle of set to one. Particularly insidious is the fact that this code is
visually differentiating semantic differences. Students have perfectly legal and compiles without even generating a
enough trouble mentally separating the concepts of declara- warning under many compilers.
tion and usage, without the syntax conspiring to blur that A less obvious example of syntax violating expectations
crucial difference. is the use of % as a comment introducer in Turing. The fol-
Other examples of detrimental cleverness are less obvi- lowing code is syntactically correct and semantically valid,
ous, but still easily come by. For example, some languages but will result in unexpectedly low pass rates:
(ABC, Haskell and Python, for instance) use indentation to
specify scope. This eliminates the need for grouping con- passMark := maxMark * 50%
structs (such as bracketing or BEGIN...END pairs) but fails Semantic violations of expectation are even less excus-
to take into account the apparently inability of many stu- able, but regrettably more common. For example, consider
dents to master the concept and practice of consistent in- the list type in the ABC programming language. A novice,
denting. Indentation-based scoping also eliminates the use- having written a seemly straight-forward program to store a
ful redundancy of employing both syntax (delimiters) and list and then print the first element:
convention (indenting) to reinforce semantics. PUT {"first"; "third"; "fifth"} IN list
Sometimes a genuinely clever idea can be sabotaged by WRITE list item 1
its own syntax. For example, in Turing dynamic memory may well be considerably puzzled and disheartened when
may be partitioned into strictly typed "collections" which the program prints: "fifth"
are then capable of storing dynamically allocated instances The blame for this minor failure can hardly be laid on
of a single data type. Pointer variables may be associated the novice, who may simply have forgotten (or perhaps
with a particular collection and can only be used to refer to never grasped) that ABC lists are automatically sorted on
data within that collection. This approach provides strong input. The fault lies squarely with the language designers,
type checking of dynamic memory and enables the compiler for although a sorting function is an extremely useful ca-
to catch and accurately diagnose the majority of common pacity in a language, hidden side effects such as this can be
pointer manipulation errors. highly confusing for the inexperienced user, especially
Unfortunately, this genuinely clever idea is disastrously when the "magic" gets in the way of the programming task.
undermined by poor choice of syntax: Even the semantics of fundamental and nearly universal
% DECLARE A COLLECTION STORING SomeDataType programming memes, such the while loop and the finite
var collectionName: precision integer, can be surprisingly difficult for students
collection of SomeDataType to comprehend. A while loop doesn't execute "while" its
% DECLARE A POINTER condition is true, but rather until its condition ceases to be
var ptr : pointer to collectionName true at the end of its associated code block.
Finite precision integers don't obey the familiar rules of
% INSTANTIATE A NEW OBJECT OF SomeDataType
whole number arithmetic and can also cause much confu-
new collectionName, instance
sion when overflow, underflow or truncation produce
Students immediately (but erroneously) conclude that: consequential errors (which may manifest well after the
• collectionName is a variable (it's actually a actual numerical error occurred).
reference to a partition of dynamic memory and Prolog 6 offers a programming system based on predicate
does not have the full semantics of a variable.) calculus, but with silent and deadly caveats. The novice at-
• ptr can be used to point to collectionName tempting to create a recursive definition (of a list member-
(it can only be used to point at instances of ship predicate, for example) will quite reasonably construct
SomeDataType allocated within the partition something like:
accessed via collectionName.) member(X,[_|Y]) :- member(X,Y).
• instance is a new instance of type collec- member(X,[X|_]).
tionName (instance points to an instance of
type SomeDataType newly allocated within which is logically quite correct, but which always fails be-
collectionName.) cause the declaration order of predicates determines the se-
quence of predicate unification in Prolog.
The Prolog equality operator (X=Y) violates expecta-
7. Violation of Expectations. tions in another way, in that it implies an assignment of
reference as a side effect:
As the last example in the previous section indicates,
violating a reasonable expectation is probably the worst
6 Although Prolog is rarely used as an introductory programming
pedagogical sin that an introductory programming language
language, many more advanced students eventually find themselves in
the role of Prolog novice.
"If X is an uninstantiated variable and if Y is any ob- 2. Differentiate semantics with syntax.
ject, then X and Y are equal. As a side-effect, X will
Novices experience great difficulty in building clear and
be instantiated to whatever Y is. [When X and Y are
well-defined mental models of the various components of a
both uninstantiated,] the goal succeeds, and the two
programming language. Syntactic cues can be of significant
variables share. If two variables share, then when-
assistance in differentiating the semantics of different con-
ever one of them becomes instantiated to some term,
structs.
the other one automatically is instantiated to the
Constructs which may, to the accomplished program-
same term." [18 ]
mer, seem naturally similar or analogous in concept, func-
tionality, or implementation (for example: using the integer
Seven Steps Towards More "Teachable" subset {0,1} as a substitute for a true boolean type, arrays
Languages being analogous to discrete functions of finite domain and
range, arrays being implemented via pointers) still need to
1. Start where the novice is. be clearly syntactically differentiated for the novice.
We believe it is misguided to highlight the similarities
A fundamental aspect of learning is the process of as- between such constructs with similar (or worse, identical)
similating new concepts into an existing cognitive structure syntaxes, because it initially blurs the crucial differences by
[19,20,21]. This process, known variously as connecting, which students can first discriminate between programming
accretion or subsumption, is made all the more difficult if concepts, and later robs them of the opportunity to consoli-
parts of the existing structure have to be removed date understanding by identifying these underlying concep-
(unlearning) or restricted (exceptions). Hence, the novice tual connections themselves.
who must unlearn that × or • means multiply, and then sub-
stitute * in a programming context, faces a harder learning 3. Make the syntax readable and consistent.
task than the student who can continue to put their knowl-
edge of × to use. Similarly, students have a large corpus of Novice programmers, like all novices, have a weak
knowledge regarding integer and real arithmetic, which grasp of the "signal" of a new concept and are particularly
cannot be capitalised upon if they must disregard it to cope susceptible to noise. This suggests that an introductory pro-
with finite precision representations. gramming language should aim to boost the conceptual sig-
Another example of this type of difficulty is the use of nal and reduce the syntactic noise. One obvious means of
= variants for assignment. Many students, when confronted improving the S/N ratio is to choose a signal with which the
with this operator, become confused as to the nature of as- recipient is already familiar. For example: if rather than
signment and its relationship to equality. For example, see- cond, head/tail rather than car/cdr, × rather than *.
ing the following sequence of statements : Another approach is to select signals which are consis-
X = 3; Y = X; Y = 7; tent, distinct, and predictable. For example, delineating
novice students sometimes expect the value of X to be equal code blocks within constructs by <name>...end<name>
to 7 (since "Y and X are equal"). The equivalent sequence: pairs:
loop
X ← 3; Y ← X; Y ← 7; if isValid(name)
seems to evoke less confusion, possibly because the syntax exit loop
reinforces the notion of procedural transfer of value, rather end if
than transitive equality of value. output name
We have shown over one thousand novice programming name ← getNextName()
students the C/C++ expression: end loop
"the quick brown fox" + "jumps over a lazy dog" It can be difficult to steer an appropriate path between
and asked them what they believe the effect of the + sign is. the syntactic extremities of "less-is-more" and "more-is-
Not one of them has ever suggested that the + sign is ille- more". On one hand, reducing syntactic noise might involve
gally attempting to add the address of the locations of the minimizing the overall syntax, for example:
first characters of the two literal strings. Without exception,
if x ≠ y if (x <> y) {
they believed that the + should concatenate the two strings.
We believe that introductory languages should be de- y ← x y:=x;
rather than
signed so that reasonable assumptions based on prior non- else }else{
programming-based knowledge remain reasonable assump- x ← y x:=y;
tions in the programming domain. In other words, the con-
structs of a teaching language should not violate student ex- }
pectations. Note that this principle has both syntactic and Alternatively, it may be better to increase the complex-
semantic implications in the selection and definition of op- ity of the syntax in order to reduce homonyms which blur
erators, functions and inbuilt data types.
the signal. For example, the meaning of the various compo- with an associated exit loop command which may
nents of the Turing expression 7 : be controlled by if statements within the loop.
f(C(p).A(I))(N) • A single generic list meta-type, allowing the user to
define homogeneous or heterogeneous lists, indexed
might be better conveyed with the syntax:
by any well-ordered type (numeric, boolean, string).
f(C::p->AI)[N] • A single, consistent model and syntax for I/O.
The second form, whilst regrettably no more mnemonic
than the first, does at least provide adequate visual differen- 5. Be especially careful with I/O.
tiation between pointer dereference, array indexing, func-
tion call, and substring extraction. With growing awareness of the importance of software
usability, it is natural that students should be encouraged to
4. Provide a small and orthogonal set of features. engineer the input and output of their programs carefully.
Too often, however, they are hampered by "more-is-more"
Homonyms and synonyms are an acute problem in the programming language I/O mechanisms which are need-
design of a teaching language. We believe the best way to lessly ornate or complicated.
minimize these pedagogical impediments is to select a The essence of I/O is very simple: send a suitable repre-
small set of non-overlapping language features and assign sentation of a value to a device. The complexity frequently
them distinct (and mnemonic) syntactic representations. observed in the I/O mechanisms of introductory languages
A side effect of this recommendation is that, as the often stems from a desire to provide too much control over
number of language constructs is restricted, those which are the value conversion process.
chosen must inevitably become more general and probably Somewhat surprisingly, the C++ language, not other-
more powerful. In particular, we believe that it is important wise known for its friendliness towards the novice8 , pro-
to provide basic data types at a high level of abstraction, vides a reasonable (if over-featured) model of I/O. Turing
with semantics which mirror as closely as possible the also offers a very straightforward I/O model and syntax.
"real-world" concepts those data types represent. We believe that the I/O mechanism for an introductory
For example, we would suggest that an introductory lan- language should be defined at the same high level of ab-
guage should not provide separate data types for a single straction as the other language constructs. We see the basic
character and a character string. Rather, there should be a features of a good pedagogical I/O model as being:
single "variable length string" type, with individual charac- • a simple character stream I/O abstraction, with spe-
ters being represented by strings containing a single letter. cific streams (for screen, keyboard, and files) repre-
A full complement of string operators should be supplied, sented by variables of special inbuilt types.
with operators for assignment, concatenation, substring ex- • uniform input and output syntaxes for all data types
traction, comparison, and input/output. In addition, a set of (for example, infix "input" and "output" operators
suitable inbuilt functions (or predicates or methods, accord- which may be applied between a stream object and a
ing to the language's paradigm) should be provided to im- heterogeneous list of values and/or references)
plement other common operations for which operators may • a default idempotent9 I/O format for all data types
be inappropriate (for example: length of string, case trans- (including character strings and user defined types),
formations, substring membership, etc). As character strings with appropriate formatting defaults for justification,
may be strictly ordered, the string type should be a valid in- output field width, numerical precision, etc.
dexing type for case statements and user defined arrays. • a reasonable, automatically-deduced output format for
Likewise, we suggest that an introductory language need user-defined data types (for example, output each
only provide a single numeric data type which stores ratio- globally accessible data member of a user-defined
nal numbers with arbitrary precision integer numerators and ADT, one value per line)
denominators. The restriction to rationals still allows the • a simple and explicit syntax for specifying non-de-
educator to discuss the general issue of representational lim- fault output formatting (for example: a generic
itations (such as the necessary approximation of common leftjustify function to convert any value to a
transfinite numbers such as π and e), but eliminates several left-justified character string of specified field width.)
large classes of common student error which are caused by
misapplication of prior mathematical understanding to fixed 6. Provide better error diagnosis.
precision arithmetic. A single arbitrary precision numeric
type has the additional benefit of eliminating many hard- There is a widely cherished belief amongst educators
ware dependence problems. that one of the ways students learn best is by making their
Other features which might be provided include: own mistakes. What is often neglected is that this mode of
• A single non-terminating loop construct, possibly
modelled on the Turing or Eiffel loop statement, 8 or indeed towards the expert!
9 Idempotence of I/O means that outputting the value of a variable and
then reading that output value back into the same variable has no dis-
7 "Create a substring consisting of the Nth letter of the string returned by cernable overall effect. String I/O is non-idempotent in most program-
the function f when passed the Ith element of the array member A of the ming languages, because strings are typically written out in their full
object within collection C which is pointed to by p". length, but read in word-by-word (ie: to the first white-space character).
learning is only effective if a student's otherwise random provide multiple levels of detail in error messages (possibly
walk through the problem space can be guided by prompt, through a "tell-me-more" option).
accurate, and comprehensible feedback on their errors. Common compilation errors (such as omitted end-of-
Making and correcting an error is certainly a useful ex- statement markers or mismatched brackets) should be accu-
perience for expert and beginner alike, but the process of rately diagnosed and clearly reported. Cases where the root
correction can be tortuous without meaningful guidance. cause of an error is not easily established should be reported
Compiler error messages are often couched in unnecessarily as problems of uncertain origin, with one or more suggested
terse and technical jargon which serves only to confuse and causes offered in suitably non-committal language.
distress the student. By the time the messages have been Run-time errors should likewise be clearly and accu-
deciphered and explained by a teacher or tutor, any useful rately reported, at the highest possible level of abstraction.
feedback which may have been gained has been largely It is sufficient for the expert to be informed that a segmen-
negated by the delay and stress involved. tation fault has occurred, but the novice needs a hint as to
The type of feedback that students receive when compil- whether the event was caused by an array bounds violation,
ing their programs typically runs along the lines of: an invalid pointer dereference, an allocation failure, or
Syntax error near line 4 something else entirely.
Not implemented: & of =
No subexpression in procedure call 7. Choose a suitable level of abstraction.
Application of non-procedure "proc"
When first introduced to programming, students often
Even should they manage to compile their program, run have trouble finding the correct level of abstraction for
time errors typically produce useful feedback like: writing algorithms. Some expect a very high level of under-
Segmentation violation: core dumped standing from the computer, to the extent of assuming that
Application "unknown" exited (error code 1) variable names will affect the semantics of the program (for
<<function>> example, believing that naming a function max is sufficient
to ensure that it computes the maximum value of its argu-
Error diagnosis is a weak point of most compiler tech- ments). Others attempt to code everything, including basic
nology, yet it is this compiler feature that novices spend control structures, from scratch. To require algorithms to be
most of their time interacting with. Whilst well-designed er- coded in languages with extreme levels of abstraction (for
ror feedback is not unknown (Turing is exemplary in this example: high-end logic, functional or pure object-oriented
respect) many language implementations, particularly inter- languages, or low-level assembler) merely compounds the
preters, have little or no error diagnosis. In these cases, er- students' already abundant confusion.
rors are detected when the program executes in some unex- It is critical for an introductory language to approximate
pected way. Detecting and correcting errors in these imple- closely the abstraction level of the problem domain in
mentations can be extremely difficult, particularly for a be- which beginners typically find themselves working. Hence
ginner, who may be uncertain what the expected behaviour it is appropriate to provide language constructs suitable for
of the program actually was. dealing with basic numerical computing, data storage and
For an introductory language, error messages should be retrieval, sorting and searching, etc. For most introductory
issued in plain language, not technical jargon. They should courses, language features which support very low-level
reflect the syntactic or semantic error that was discovered, programming (for example: direct bit-manipulation of
rather than the behaviour of the parser. Error diagnosis must memory) or very high-level techniques (such as continua-
be highly reliable or, where this is infeasible, error mes- tions) will merely serve to stretch the syntax and semantics
sages must be suitably non-committal. For example, given of the language beyond the novice's grasp.
the statement:
int F(X); // WHERE X IS AN UNDECLARED TYPE
Seven Criteria for Choosing an Introductory
a widely-used C++ compiler emits the error message: Language
')' expected
rather than explaining that: Each of the preceding design principles also provides a
An unknown type 'X' was used in the criterion against which to evaluate the suitability of existing
parameter list of function 'F'. programming languages for introductory teaching. We
would suggest that when evaluating a potential teaching
In this case even a vague message like: language, in addition to addressing the usual considerations
There seems to be a problem with the (such as language paradigm, compiler availability, textbook
parameter list of function 'F'. quality, establishment and maintenance costs, popularity,
would be of more use. etc.), educators should also bear in mind the seven "sins"
We suggest that a fully-specified error reporting mecha- we have enumerated. The key questions are:
nism should be an integral part of any introductory pro- • Is the syntax of the language excessively complex
gramming language definition. Such a mechanism must (and therefore lexically "noisy") or too sparse (and
mandate plain language error messages and should ideally therefore insufficiently discriminating)? Are there
syntactic homonyms, synonyms or elisions which ming languages must evolve through prototyping rather
may confuse the novice? than springing fully-formed from the mind of the language
• Are the control structures, operators and inbuilt func- designer.
tions of the language reasonably mnemonic? Are they
likely to be consistent with students' previous References
(mathematical) experience? How much "unlearning"
will they require of the novice? [1] Wirth, N. and Jensen, K. Pascal User Manual and
• Are the semantics of the language inconsistent, ob- Report, Springer-Verlag, 1975.
scure, or unnecessarily complicated? Are there con- [2] Holt, R.C. and Hume, J.N.P., Introduction to
structs whose invocation, behaviour or side-effects Computer Science using the Turing Programming
are likely to confuse a student or violate novices' rea- Language, Prentice-Hall,1984.
sonable expectations? [3] Geurts, L., Meertens, L. and Pemberton, S., ABC
• Are the error diagnostics clear and meaningful at a Programmer's Handbook, Prentice Hall, 1990.
novice's level of understanding? Are they unambigu-
[4] Kernighan, B. and Ritchie, D., The C Programming
ous, detailed and not overly technical? Are they accu-
Language, 2nd ed., Prentice-Hall, 1988.
rate where possible and non-committal otherwise?
• Are parts of the language subject to unnecessary [5] Stroustrup, B., The C++ Progarmming Language,
hardware dependencies or implementation-related 2nd ed., Addison Wesley, 1991.
constraints? Will necessary restrictions be difficult to [6] Barnes, J.G.P., Programming in Ada, Addison-
explain to the novice? Wesley, 1994.
• Is the language too big (over-featured) or too small [7] Harbison, S., Modula 3, Prentice Hall, 1992.
(restrictive)? Is the level of abstraction of the lan- [8] Hudak, P. and Fasel, J.H., A Gentle Introduction to
guage constructs appropriate for the practical compo- Haskell, SIGPLAN Notices, 27(5), May 1992, ACM
nents of the course? [9] Springer, G. and Friedman, D.P., Scheme and the Art
• Are the apparent virtues of the language equally "ap- of Programming, The Massachusetts Institute of
parent" from the novice's perspective? Alternatively, Technology, 1989.
are they a product of the educator's familiarity with [10] Feuer, A. and Gehani, N., Comparing and Assessing
the candidate language or with the languages which Programming Languages: Ada, C, and Pascal,
were the candidate's genetic and memetic influences? Prentice-Hall, 1984.
In the real world it is clear that the choice of any one [11] Conway, D.M., Criteria and Consideration in the
language must necessarily be a compromise between eco- Selection of a First Programming Language,
nomic, political and pedagogical factors. The relative im- Technical Report 93/192, Computer Science
portance of each of these considerations will depend on the Department, Monash University.
specific aims and priorities of the institution, educator and [12] Koelling, M., Koch, B., Rosenberg, J., Requirements
course. Unfortunately, all too often pedagogical factors are for a First Year Object-Oriented Teaching Language,
neglected, or sacrificed to more obvious and prosaic con- Techical Report 94/488, Computer Science
cerns. We believe that this approach undermines the ulti- Department, Sydney University.
mate goal of successful student learning. [13] Mody, R.P., C in Education and Software
Engineering, SIGCSE Bulletin, 23(3), 1991.
Conclusion [14] Wilensky, R., LISPcraft, Norton, 1984.
[15] Hofstadter, D., Gödel, Escher, Bach: an Eternal
We have enumerated seven ways in which introductory Golden Braid, Part II, Chapter 10: "Similar Levels",
programming languages conspire to hinder the teaching of Basic Books, 1979.
introductory programming and have also suggested seven [16] Stroustrup, B., The Design and Evolution of C++,
principles of programming language design which may help Addison-Wesley, 1994.
to reduce those hindrances. We do not suggest that either
[17] Holt, R.C., Matthews, P.A., Rosselet, J.A., Cordy,J.R.,
list is exhaustive, nor that the principles we expound are
The Turing Programming Language: Design and
definitive or universally applicable. The design of any pro-
Definition, Prentice Hall, 1988.
gramming language is an art, and the design of a language
whose purpose is to teach the fundamental concepts of pro- [18] Clocksin, W.F. and Mellish, C.S, Programming in
gramming itself is high art indeed. Prolog, Springer-Verlag, 1981.
Just as no battle plan survives contact with the enemy, [19] Thorndike, E.., The Fundamentals of Learning, New
no pedagogical language design (no matter how sound its York: Teachers College Press, 1932.
design principles or clever their realization) can hope to [20] Ausubel, D., The Psychology of Meaningful Verbal
survive contact with real students. Yet the outcomes of such Learning, Grune & Stratton, 1963.
encounters are the only meaningful measure of the success [21] Rumelhart, D. and Norman, D., Accretion, tuning and
of an introductory language. This implies that the most im- restructuring: Three modes of learning, In. W. Cotton,
portant tool for pedagogical programming language design J.and Klatzky, R. (eds.), "Semantic Factors in
is usability testing, and that genuinely teachable program- Cognition", Erlbaum, 1978.

You might also like