Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!linus!philabs!prls!pyramid!pesnta!valid!sbs From: sbs@valid.UUCP (Steven Brian McKechnie Sargent) Newsgroups: net.lang.c Subject: Re: Boolean Operators Slighted in C Message-ID: <268@valid.UUCP> Date: Thu, 8-May-86 07:39:00 EDT Article-I.D.: valid.268 Posted: Thu May 8 07:39:00 1986 Date-Received: Sun, 11-May-86 00:36:07 EDT References: <778@bentley.UUCP> <791@bentley.UUCP> Organization: Valid Logic, San Jose, CA Lines: 133 This group has lately been besieged with a variety of odd C features, namely * boolean operators and data types * builtin functions * New operators like "< =" * Arguments passed in registers All these have the same effect of reducing simplicity for doubtful gain. ** A Boolean data type distinct from integers clutters the language with another (moderately useless) type and removes handy idioms like foo[x == 0] = bar; (Vide the "enum" type, which doesn't participate in address arithemtic either.) Arguments that boolean functions make for more efficient implementations are pretty puny: > o A function returning a bool could be implemented on some machines by > setting the condition codes instead of storing a full integer value in > the return register. If the caller wants to use the result of the function as a value, rather than as input to a branching decision, then it must write branches anyway to set the value appropriately. Result: bigger slower code. > >o Multiple flag variables with local scope and no address operator (e.g. > > variables declared "register bool") could be packed into a single word. Last I checked, (flags&BOOLEAN_VALUE_OF_MERIT) did what you want. Packing and unpacking don't come for free, in space or time. ** Builtin functions confuse language implementation with programming environment implementation; C lives in enough different environments that this is just plain bad planning. "Inline functions," a la those of C++, are another matter entirely (although they have been mentioned repeatedly in discussions of builtin functions). The benefits that inline functions offer over CPP macros are: simpler cleaner syntax, more flexibility because they admit arbitrary control structure within, and avoidance of horrible botches like putchar(*p++). The disadvantage, at least in my mind, is uncertainty as to what happens to the free variables of an inline function. Are they bound lexically where the inline is declared, or are they bound at the point where the inline is used, assuming the nearest enclosing scope? Consider: int oddval; // Not odd, as in = 1 (mod 2), but "odd" inline max(x, y) { ++oddval; return (x > y)? x: y; } foo(oddval) { int n = max(oddval, 0); oddval = max(4, oddval); return max(oddval, oddval); } bar(x) { ... return max(x, 4); } The question that leaps to mind is "what the hell does this code hope to achieve?" You can of course write just as silly code using the C preprocessor; but then the question becomes: Why provide redundant ways to write this unsafely? ** New operators like "< =", in addition to being hard to spell and understand, facilitate usages that just aren't that common. I hardly ever want to say x = (x < y), and I don't mind typing the extra characters. I'm not interested in paying compiler vendors money for supporting this (or any other dubious misfeature pounded into the language for "completeness' sake.") ** There's also been a discussion about arguments passed in registers, with one fellow (sorry I forget the name) noting that "microcomputer people pass arguments in registers." Well, big computer people do the same thing, and in both cases the disease is one of not thinking through to the consequences of your actions. Suppose you pass arguments in registers. Well, if you're like me, you have a lot of variables in registers. So in order to pass your arguments, you have to save those registers somewhere. Where do you do it? Put them on the stack, of course. Well, suppose that you "know" that %3 and %4 are reserved for parameter passing: then those registers are unavailable to the caller, whose code gets correspondingly bigger and slower. Well, suppose you're keeping the arguments in %3 and %4, and the callee can use them "in place" because caller and callee have agreed to do that (in order to avoid the overhead of explicit parameter moving). Now, you're writing spaghetti code, full of "special" communication among routines, with all the attendant side effects and untraceable bugs. And why for? The speed gain from non-standard calling sequences seems marginal at best: one recent posting discussed at great length the most efficient way to present arguments to the UNIX open(2) call -- which executes hundreds or thousands of instructions inside namei, involving perhaps multiple waits for the disk in order to fetch the inode for the file! Put the arguments on a linked list of bit-wide elements and force the kernel to chase them down, if you want: it won't make much of a difference in how fast your programs run. ** It's lots of fun to talk about wonderful "features" we'd like to see, but somebody (ANSI?) might be listening and do something about it. So, for my $.02 worth: * Always strive to separate language from libraries, libraries from host environment, and host environment from development environment. These are all separate entities; make their interactions as clean as possible. * Keep implementations simple. This means: eschew oddball calling sequences that are hard for debuggers to follow. This means: minimize the number of compile-time options -- the user needs to determine the meaning of his program from the source code; don't confuse the process by throwing in options that invisibly change this meaning. * Be EXTREMELY conservative about adding features. I have yet to see a feature proposed that fixes a crippling problem of the language. Quite the opposite: many proposed features, such as unary + to denote evaluation ordering, help a min- ority of users while making the language more baroque for everybody. I do go on, don't I? Oh, well; enjoy, flame back, or whatever. Blessed be, S.