Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!columbia!rutgers!sri-unix!sri-spam!ames!ucbcad!ucbvax!BRL.ARPA!gwyn From: gwyn@BRL.ARPA (Doug Gwyn, VLD/VMB) Newsgroups: comp.sys.apple Subject: Re: The C language Message-ID: <8705271800.aa08301@VGR.BRL.ARPA> Date: Wed, 27-May-87 18:00:02 EDT Article-I.D.: VGR.8705271800.aa08301 Posted: Wed May 27 18:00:02 1987 Date-Received: Sat, 30-May-87 07:02:41 EDT Sender: daemon@ucbvax.BERKELEY.EDU Distribution: world Organization: The ARPA Internet Lines: 293 > From: John Perry > I have actually written about twice as much C code as Pascal or > Modula-2 code and so my criticism of C is not made solely at an "airy" > theoretical level. That doesn't follow at all. Your criticisms amount to complaints that C does not meet some ideal model you have in mind for a programming language. As will be shown, your understanding of C is superficial, and evidently hampered by your prejudices. I'm not objecting to that in itself, but to the fact that you are making recommendations based on such views. > You say that "If C is so terrible, then how do you explain so many > commercial software developers switching to it?". I thought I answered > that in my previous memo i.e. that some languages have dirty details > that make them so desirable in a practical sense that programmer's > are willing to overlook even the grossest of structural defects. I see. It's not utility you seek, but unusable structural "perfection". The things that make C a better language for practical work you call "dirty details", as if attention to such matters weren't fundamental. We're about to investigate what you apprently identify as these "gross structural defects" (of course your favorite language couldn't possibly have any defects, could it -- they'd just be "minor imperfections"). > ... Well, as you > put it, C is "good enough" --- the typical sunk-cost outlook --- another > tool has to be 100% better to justify a changeover. That's not an accurate assessment. It is a waste of time to design yet another programming language that has comparable facilities to existing ones, unless it is clearly superior in several significant respects (which has not been demonstrated in this debate). One sufficiently good language of each general type is plenty. Programming languages are TOOLS, not ENDS IN THEMSELVES. (Leaving aside educational considerations.) > C, when examined closely, is so full of inconsistencies and > unnecessarily cryptic syntactical finesses that, and I will reiterate > my practical observation, that even good C programmers can be seen > consulting a C manual even after several years of practice! The only thing I've seen people whom I would consider to be good C programmers look up (infrequently) about the language is the precedence of operators in expressions, in cases involving combinations of bitwise, shift, conditional, and assignment operators. (Some programmers would simply use extra parentheses to be sure, rather than look up the precedence.) Most programming languages don't have this problem because they're not capable of supporting such expressions in the first place. I will admit, as will any good C programmer, that the bitwise operators would have been more conveniently given higher precedence than the equality operators. We're used to it, though, and again many languages don't have that problem because they force more cumbersome expression in the first place. Occasionally one will look up the order of arguments to one of the vast number of infrequently-used functions in the C library. Generally one needs to check the functional specification anyway at that point. That would apply equally to any language. (Keyword parameters are only useful if you remember everything about the interface except parameter order; they might be a useful addition to C some day if a good syntax could be devised (name=value already has another meaning).) > First, inconsistencies in parameters of library calls. Why is it > that, in an fprintf statement, the file is the first parameter but in > a putc statement it is the SECOND parameter? Because putc(c,f) was considered to be the natural way to order "put character to file". The printf() family have to support variable parameter lists, and that consideration forced the parameters to come last. At least C HAS variable parameter lists! > And why, oh why, does C > have to be different than the rest of the world by making the destination > string be the FIRST parameter in string subroutines such as strcat? I tried explaining this by analogy with dst:=src, but you seem to have missed the point. It could have been done either way, just so long as the str*() functions are consistent in this (which they are). Another response would be, your concept of the "rest of the world" is seriously limited in scope. Why isn't Modula-2 just like Fortran in everything it does, hmm? Isn't that what the "rest of the world" does? > Oddly enough, in the original Kernighan and Ritchie C book, their version > of strcpy has the destination string as the second parameter on page 100 > --- why the change to the counterintuitive in commercial C? I knew already you were a C illiterate; this proves it. K&R's strcpy() is compatible with the one in the standard C library. In fact, they explain why the parameter order is the way it is, in much the way I did. Or maybe you don't read English either? Again, what you consider "intuitive" is not necessarily universal. If I had no prior experience with dst:=src or MOV DST,SRC then I admit I would have a slight inclination toward strcpy(src,dst), and I normally design function interfaces with input parameters followed by output parameters, but the other way around doesn't bother me either. Why is this so important? Do you program by trying to GUESS how things work instead of LEARNING how things are used? Maybe it's a good thing that C does bite the sloppy craftsman; it might lead to improved work habits. > Second, inconsistencies in rules for structured data types. Can > anybody give me a good reason why arrays cannot be assigned in assignment > statements as can structures? Another artificiality that one must keep > in mind. Yes: the name of an array in C is a pointer to the first element of the array. You CAN assign the name of an array to an appropriate pointer variable. There simply is no syntax for specifying assignment of the entire array. The memcpy() function can of course be used for this when it is necessary to copy an array into another. In C, that is an infrequent situation, because pointers to objects are so easy to use that whenever possible experienced C programmers will copy pointers, not the objects they point to. After all, that's more efficient and C was specifically designed for use in efficient systems programming. C's identification of array names with pointers has been extremely useful. It unfortunately had the side-effect of making arrays themselves "second-class" data objects with respect to some operations, but then virtually all languages do this. (You cannot meaningfully divide scalars by arrays, for example.) > Third, C's allowance of mixing pointer and array types leads to > abominably unreadable code. In some UNIX sources I have seen such > mixtures leading to oddities like a[3] meaning "the third value after > where the pointer to a is currently pointing" rather than simply the > fourth value of the array. Try reading this kind of stuff and keeping > your sanity. Experienced C programmers virtually never access the nth element like this for n other than -1, 0, or 1. Try reading the equivalent operation (with a pointer!) in other languages and see if you're saner. The reason for the parenthetical qualification in the previous sentence is that pointers are often the natural way to access objects in C, unlike Pascal for instance where array indices are easier to use in practically all cases. C use of array indexing would look much like Pascal's, but often that is not the natural way to effectively exploit C's facilities. > Fourth, the simple C data declaration: > > int *pi; > > gives you no clue whether pi points to a SCALAR integer or an ARRAY > of integers. This kind of ambiguity does not exist in Modula-2 > or Pascal where the declaration of pi would tell us whether we have > a pointer to a scalar or structured data type. In your example, `pi' is a pointer to an (int) object, just as the declaration says. The object might be one of several organized as an array, or it might not. A pointer to an array would be declared as int (*pi)[]; where the array dimension may optionally be specified (in such cases, the only dimensions that must be specified in C are the ones necessary to determine how to locate an array entry). I realize you probably intended the point addressed by the second sentence in my paragraph above. Why is that a problem? It follows naturally from the very language structure that makes x[y] == *(x+y); again your complaint seems to be that C uses different abstractions from the ones you're happy with. That is simply a matter of upbringing and personal taste, unless you can demonstrate objectively that one alternative is superior on all counts of real-world value, which I doubt very much you can do. > Fifth, C's rules for initializing character arrays, especially > "ragged" arrays of variable length characters, seems to differ from > implementation to implementation. You want standards, we're about to publish one. There's no ambiguity in the standard language specification about this. The only possible ambiguity in current non-buggy implementations would concern whether or not to diagnose the following as an error: char s[2] = "xy"; (since the initializer seems to require space for its NUL terminator). This is a rather rare situation. Otherwise, the rules are quite clear. > Sixth, C allows an unreadable degree of programmer cleverness > as in such code segments as: > strcpy(s,t) > char *s,*t; > { > while(*s++ = *t++);} > > Which relies on the artifact that a string terminator happens to be an > ASCII zero and that, since the value of an assignment statement is the > value of the left hand side, the while will terminate when NULL is > encountered. C moguls actually ENCOURAGE this kind of "idiomatic" > expression e.g. Kernighan and Ritchie -- "Although this may seem cryptic > at first sight, the NOTATIONAL CONVENIENCE (my emphasis) is considerable, > and the idiom should be mastered ...". First of all, use the right whitespace, comments, etc., as in the reference you gave but did not understand: strcpy(s, t) /* copy t to s; pointer version 3 */ char *s, *t; { while (*s++ = *t++) ; } Next, note that C strings are terminated by 0-valued (char)s; this is true no matter what the target character set -- ASCII has nothing to do with it. It does not "happen" by accident but is a key feature of C character strings directly supported by the language (one can define count+data style strings etc. himself if desired). By the way, nobody I know of (including K&R) recommends using NULL as a symbol for anything in C other than a null pointer, which is not the same as the string terminator (invariably written as '\0' or simply 0). The rest of the quotation, which you elided from your biased summary, is "..., if for no other reason than that you will see it frequently in C programs." This is a perfectly valid point for a text teaching C to make, and the implication is that one might want to consider whether one should write code like this oneself. As a matter of fact, many experienced C programmers (including myself) would show the comparison against the 0-terminator explictly. We would probably change other details of the strcpy() implementation, for which K&R showed four different versions, of which you selected the one that is specifically intended to help explain one of the more obscure commonly- encountered idioms. Note that K&R do NOT use that style in subsequent examples. This hardly constitutes "encouragement". > By notational convenience they mean THAT IT CAN BE TYPED IN > QUICKLY!!! And, of course, the "idiom should be mastered" if one is > to enter the pantheon known as "C cognoscenti" --- God forbid if > one's C code looks like that of a Pascal programmer!! I'm not sure what a "Pascal programmer"'s code looks like. (I thought it varied from programmer to programmer, depending on training, experience, thoughtfulness, organizational standards, etc. Funny that C should be considered immune from these sources of variation.) Certainly my C code doesn't look like the picture you try to paint of code of "C cognoscenti" (which I take to mean "those who know what they're doing when it comes to C" -- is that meant to be derogatory?). > I could rant on and on about the poor human engineering of the C > language (how many times have you gotten caught on if a = c instead > of if a == c Never. > or *p++ versus (*p)++ ??) Never. > and get even further bogged > down in the "features" quagmire. But to what end?? C deliberately has few "features", in the sense of unnecessary frills. It does have "features" in the sense of useful facilities for doing certain types of jobs effectively. It is by no means one of the "big" languages (PL/I, Ada, etc.) > ... On the other hand, I feel that the > basic skeleton structure of a language like Modula-2 is so sound that > the addition of precious few features and a couple minor language > changes would create a nearly ideal programming tool. Yes, one gathers you believe that. Unlike you, I'm not about to criticize a language for attributes I don't fully appreciate or because it isn't just like my favorite language. > But, it'll probably never happen because the artificialities > and ambiguities of C create the sort of mystique about the "difficulties > of programming" that programmers love. Next to chess players, their > egos are the most insufferable. How long have you had this complex? Seriously, C was designed by software developers for use by software developers in a particular unregulated type of development environment. If the environment had been like those favored by structured design methodologies (which were barely in their infancy when C was designed), C very likely would have "package"-like facilities rather than the more simple (and more universally supported by linkers) linkage it provides. C was never intended to be a Beginner's All-purpose Symbolic Instruction Code, nor a teaching tool (Pascal), nor something intended to be read by business managers (COBOL), nor a replacement for myriads of specialized languages for embedded systems (Ada). The real reason professional programmers are jumping on the C bandwagon is that C was designed for use by professional programmers; they find it an effective tool for developing applications. This is no more a "mystique" than a carpenter's preference for tools that an unskilled layman would have a hard time using properly. If YOU PERSONALLY don't happen to like C, you don't have to use it. However, it is morally and ethically WRONG to make recommendations to people who might be looking for advice when you can't do so fairly. In this context, fairness would require that you evaluate the languages in comparable terms -- to state that one of them has serious structural flaws while the other is nearly perfect is simply not true and might mislead the innocent (of which I'm fortunately not one).