<<

Why ? a roundabout answer

I. Refresher

C was preceded by a named B (circa 1970). B in turn evolved from a much older command programming language named BCPL. Command programming languages, in contrast to high order programming languages, are relatively modest languages designed to manipulate the computer's operating environment rather than solve general computational problems; they are the forerunners of today's modern computer operating systems.

C is the brainchild of a Bell Laboratories scientist named , developed to go hand and glove with the . Unix in turn is attributed to another Bell Laboratories scientist named (who also authored B). The fact that well over 90% of Unix can be described by using programs written in C is what makes it feasible to implement Unix as the operating system for a large variety of computing environments, including today's PCs. This close relationship to Unix is the major reason C has continued to be so widely implemented and used, and is a major consideration for incorporating it into computer science curricula.

It is only because AT&T was not in the computing business at the time Bell Laboratories' scientists were developing Unix and C that Unix is not a single- vendor commercial product such as MicroSoft's Windows. It is worth noting that Linux and Free BSD (Berkley Software Distribution), modern variants of Unix, are at present the only generally available alternatives to Windows for PC environments. Linux is "freeware" crafted and maintained by a fairly large group of computing professionals who don't want a computing world defined only by commercial interests. Free BSD is also “freeware”, but has its origins in proprietary systems and, unlike the Linux Gnu general public licensing, allows propriety derivatives (such as Apple’s). On the other hand, Free BSD has tighter control over recognized releases.

II. C/C++/Java – which comes first, the chicken or the egg?

Mathematicians once thought that they could eliminate steps in the process of developing students "mathematical maturity" by doing a carefully orchestrated "pre-calculus to real analysis" sequence (they were wrong). They basically forgot the (sometimes painful) processes that they themselves had gone through to gain their own level of mathematical maturity. There is a similar "computational maturity" that must be developed in students, which evolves from computational problem solving, through data and machine structures, to the abstractions that object-oriented environments seek to represent. From this perspective, the object-oriented paradigm is one that needs to be introduced later, not sooner.

C++ is just C with object-oriented extensions. Java is an object-oriented language whose syntax is derived from C/C++. A huge percentage of commercial software is written in C++. So why not "teach" C++ or Java as the first language? The better question is why not start students with the object paradigm? That approach assumes that the student has already achieved, or can acquire in parallel, computational maturity, never mind the realities of implementation and implementation environment that characterize commercial programming environments. The argument for using a commercial product in the first place is the pragmatic demand that instruction employ commercially useful software products, usually attended by a non-trivial development environment. It is altogether too easy for the complexity of such software products to shift instructional emphasis away from fundamental objectives, in effect retarding acquisition of critically needed computational maturity. While C shares some of these characteristics with C++ and Java, its level of complexity and the weight of its environment pales in comparison.

III. A First Objective

The objective of the first computing course is (or at least should be) to learn how to solve problems computationally, not how to manipulate the syntax of some flavor of high level language. The solution space for solving computational problems is captured within the C language subset of either C++ or Java. A commercial implementation of C++ or Java includes a plethora of classes, objects, and methods, many of which are ancillary to the objective of learning how to solve problems computationally. Moreover, these implementations typically come with industrial strength development environments, which also must be taught in order to use the product.

In a perfect world, we would NOT introduce students to the discipline of computing via a course titled "introduction to programming in xxx". If the first course is "intro to programming in xxx", then course emphasis is already pegged to syntax issues and the development environment at the expense of solving computational problems. Inevitably, the more complex the programming environment is, the less the emphasis on solving computational problems. Using C for solving computational problems (or C within C++) is a pragmatic choice that minimizes the impact of environment on objective. It helps that C implicitly supports a transition to object oriented development because of its syntactic relationship to either C++ or Java. C has the added advantage of its intimate relationship to Unix and its practical utility for writing low-level programs in other computing contexts.

IV. Some Noteworthy Advantages and Disadvantages of C

C has advantages other than its intimate relationship to Unix. Most noteworthy is that it can be successfully described in a very few pages, as Kernighan and Ritchie proved (their book pretty much covers everything, and includes a tutorial, a description of the Unix interface, and a lexical description of C, all in about 200 pages). Contrast this with any reference of note for Java. In C, complex structures and operations, such as those associated with I/O and strings, are relegated to libraries. This means that the syntactic structure for solving computational problems is free of clutter that can confuse the programming environment with the solution space.

C also has some very real pitfalls. First of all the syntax does not conform to lay usage, most prominently a = b vs. a == b. There are the implementation realities of the various data types. The relationship between arrays of characters and character strings exemplifies the perils and pitfalls of pointer manipulation. The very things that make the language useful for low-level programming are potential points of confusion for novices. The predefined function libraries can complicate instruction (consider the pow routine and its several variations as just one example). Of course, on the pragmatic side, many of these characteristics facilitate discussion of system programs and can be used to illustrate the nuts and bolts of the inner organization of the hardware. For example, it is easy to devise a C program to examine integers at the bit level to determine how they are implemented on a specific machine.

V. Why C?

C is a subset of the most widely used development language, C++. It is the means within C++ for solving computational problems and manipulating data. You cannot use C++ effectively until you have learned how to solve computational problems and manipulate data in C. Users often confuse the language with the implementation environment. Both C++ and Java have complex development environments making extensive use of predefined classes, objects, and methods. The underlying mechanism for solving computational problems, however, is still C. C is implicitly supported in any Unix environment, including development tools common to all Unix implementations. There are "standard" C libraries that are included with any C implementation; the structures employed in C++ or Java systems development may not survive from one release to the next.

VI. What Learning Environment?

It isn't hard to justify C as "mother tongue". It may be harder to decide on the environment in which to learn C, if for no other reason because C is used in many contexts other than Unix environments. Absent a specific context for learning to program in C, the close relationship between C and Unix tends to support using the basic Unix command line interface as the generic learning environment. Given the wide deployment of Unix systems, there is also advantage gained from working with the standard Unix environment. The counterpoint is that the Unix command interface is pretty clunky when compared to the typical desktop. However, no X-Windows standard GUI seems to be on the horizon, and program development environments for PCs, as excellent as many are, are tied to the context of single user workstations and PC operating systems. Since the Unix command line environment is the likely constant for the foreseeable future, it is the pragmatic choice for the base learning environment. Since there is an ANSI standard for C, the base environment can be supplemented (“user responsibility”) with some degree of confidence by other environments where advantageous.

VII. Denouement

Over the short history of computing, the programming of digital computers has progressed through a series of programming languages. The development of formal language theory instigated much of this work. New programming paradigms and specific application needs (first for basic systems purposes and later for user interfaces) spurred the evolution of programming languages to where we find them today. C dates from about the middle of this history, and has had an ANSI standard definition now for more than 10 years. C exist for all manner of processors, which makes the language useful for applications other than conventional application programming. The maturing of the object paradigm has led to object-oriented extensions such as C++ and languages employing C syntax, such as Java, to better serve complex systems development needs.

No programming language is without its shortcomings and C is no exception. The objective of learning how to solve problems computationally has been addressed through a spectrum of languages, perhaps initiated with . The one common thread throughout has been the use of procedural structures for decisions and loops to mimic the reasoning paradigms of mathematics. The close relationship to solving problems computationally to the solution paradigms of mathematics is why the development of computational maturity in students of computing is no less important than the development of mathematical maturity in students of mathematics. Although C has intrinsic features for dealing with commercial development needs, particularly at the systems level, it also is spare enough in its basic structural mechanisms to serve the larger purpose of promoting computational maturity. While C represents a pragmatic choice as a place to start, it has the advantage of broad practical application. Concomitantly, it serves well as a natural staging ground for advancing into the arena of pragmatic object-oriented development, whether in C++ or Java.

Reference: The C Programming Language (2nd edition) by Kernighan and Ritchie (Prentice-Hall)