David works for Berger and Company in Denver, Colorado. David can be reached at 1623 N. El Paseo St. Colorado Springs, CO 80907
n the June 1986 issue of Dr. Dobb's Journal, I wrote a "Viewpoint" entitled "What's Wrong With C." Have things changed enough to make me alter my opinion? While the title of this "Viewpoint" probably gives away my position today, it is nonetheless time to reassess the state of C, and see how it stacks up for the 1990s.
Just to recap: My two principle objections to C in the mid-1980s were: a. The quality of C compilers and their output; and b. The productivity (including the maintenance part of the software life cycle) of programmers using C. Let's put the easy one to bed quickly -- the quality of today's C compilers is dramatically better than it was a few years ago.
The popularity of a language correlates well with the quality of its compilers. The compiler vendors can afford to spend more of those expensive man-hours improving a product that sells well -- and they are compelled by competition to do so. This is why nasty (but popular) languages, such as Fortran and Cobol, often produce the tightest code in the environments where they run.
The size and quickness of the object code is (mostly) a consequence of the implementation, not the language itself. The real point is that C, with its inherently low-level nature, is much harder (but not impossible, as my 1986 article implied) to optimize to the same degree as "better" languages. I'm still willing to bet that Microsoft has many more man-months' effort invested in its C compilers' optimizing technology than, for example, JPI has in the optimization portions of its excellent Modula-2, which produces comparable code. Perhaps many times more. But, as long as someone has gone to the trouble for us, and as long as people are willing to amortize the extra cost by buying and using C in droves, then who cares? C compilers nowadays are generally "right and tight." They are production quality tools in a way much hyped and hoped for in the early 1980s, but seldom seen.
Somewhat of a corollary to C's inherently low-level, operator-rich, "portable assembler" character was an ethos I thought of as "small is beautiful." The idea was that obscure idioms are O.K. because "the notational convenience is considerable" (to quote K&R); and that C compilers did not have much to do because a truly good programmer could always build his own (ideally designed and reusable) libraries; and unerringly find the appropriate, optimal algorithm; and without fail put a finger on the right ten percent of a program to convert into assembler; or do something else beautiful (while expending practically no time) to compensate for the elegant simplicity of his tools.
Tens of thousands of people are now using C full time; it should be obvious that we are not all legendary coding paragons such as Jon Bentley, Dennis Ritchie, and Brian Kernighan. Let "small is beautiful" rest in peace. Codified ANSI C seems much less the small, informally specified, gratuitously "elegant," personal use language that was so objectionable to those facing large-scale, serious systems implementation projects. ANSI C is larger, with a more "designed by committee" feel. ANSI C is internally more complex, for the purpose of providing real-world production services, such as compile-time parameter checking, which production coding shops have come to expect and depend on.
C compilers are now presented as environments that do lots of things for the "pilot." State-of-the-art debuggers and code profilers and front ends with hypertext online documentation are conveniently (or instantly) available, as are function libraries, prepackaged to do nearly any part of an application the programmer doesn't wish to tackle. The infrastructure, which has grown up around C, has contributed enormously to the productivity of C programmers. For my money, this is as it should be and (almost) all to the good.
In most programming situations, bottom-line productivity -- man-hours to a result with some acceptable functionality -- is the most important factor separating the quick from the dead. C programmers are probably more productive than ever before; I believe it is safe to say, even without citing corroborating studies. It may be ironic that the plethora of productivity aids surrounding C grew up because raw "early C" was so idiomatic and difficult that help had a market value. Or it may be that the utilities and subordinate tools appeared for reasons having nothing to do with alleged difficulties in C. Again, who cares, as long as we got the boost we needed?
A tremendous strength of C, which I totally overlooked, is evidenced by the growth of new technologies that leverage on C's portability and low-level robustness. The very terseness and richness of C's operator set, which I bemoaned as distracting to the human programmer, makes C a good target language to be emitted from translators evincing new concepts and powers. C++ is perhaps the most famous example of this. The first C++ emitted ordinary C as its output, bringing "object oriented-ness" to C in the same way that RATFOR brought "structured-ness" to Fortran.
Even for those purists who believe that tacking on "object orientation" to an existing language is the wrong approach, C has made its contribution. For example, Bertrand Meyer's Eiffel language emits C as its object code. Eiffel is a promising, practical (not interpreted or Smalltalk-like), purely object-oriented programming system. Meyer's (recommended) book, The Design of Object Oriented Systems, uses Eiffel as its "presentation language."
When employed as an intermediate language, C's terse and impenetrable tendencies may be a decided plus. No less an authority than Knuth advises that if the emitted code is deliberately unfriendly, then people will use the front end for modifications, rather than tweaking the intermediate (C) code and causing maintenance headaches. Knuth's WEB document compiler system uses this approach, deliberately emitting "unreadable" Pascal. Arranging for your new translator to emit unreadable C should be easy; getting human beings (or anything else) to write halfway readable C appears to be the real trick.
C still is (in my mind) the consummate virtuoso's ax for "programming in the small." For large teams working on large problems, even ANSI C's improvements are not enough. I am intrigued by how much of the interest in C++ and other C variants (such as Object C and Objective C) may be due not to the attractions of object-oriented technology itself (which truly requires a shift in world view) but to the possibility that "C objects" might be used in the context of traditional design (as Modula-2 modules and Ada packages). That is, to render "programming in the large" more practical and productive, and design software modules more "plug compatible" and reusable. The perceived need is not for (yet another) fundamental paradigm shift, but rather for a way to manage implementation of large traditional designs in a language that is neither obscure, nor unwieldy, nor disdained by the best programmers. Many people appear to be examining the "right technology" (such as object oriented-ness) for the "wrong reason" (or the hope of data abstraction and reliable modularity) just because both the reason and the technology are connected with C.
It is a monument to C's mutability, resilience, and popularity among the best and brightest that C seems to be carrying the freight of the world's hope for a language which is great for the individual, nice for the team, and economical for the life cycle of a system.
Copyright © 1989, Dr. Dobb's Journal