Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!mcnc!ece-csc!ncrcae!ncr-sd!hp-sdd!ucsdhub!jack!man!nu3b2!rwhite From: rwhite@nu3b2.UUCP (Robert C. White Jr.) Newsgroups: comp.lang.c Subject: Re: Writing readable code Message-ID: <783@nu3b2.UUCP> Date: Sat, 4-Jul-87 21:46:21 EDT Article-I.D.: nu3b2.783 Posted: Sat Jul 4 21:46:21 1987 Date-Received: Sun, 5-Jul-87 09:35:55 EDT References: <1158@copper.TEK.COM> <6858@auspyr.UUCP> <17171@cca.CCA.COM> <262@auvax.UUCP> Organization: National University, San Diego Lines: 121 Summary: Assignmeqnvt100 t In article <262@auvax.UUCP>, rwa@auvax.UUCP (Ross Alexander) writes: } The following discussion is all relative to } } #define EOF -1 } char c; } while ( ( c = getchar() ) != EOF ) { /* do something */ } } } Isn't there a little room here for arguement? Now of course K&R say } that an expression is coerced to the type it is being assigned to. } This is _a good thing_, since otherwise there's no way to assign to a } char (think about the promotion rules :-). But isn't assignment, in } the strictest sense, a side effect? Or phrased a little differently, } is the comparison being made to the value of c or the value of the } getchar() ? So the coercion for the assignment of `int' to `char' in } this case is a side effect and shouldn't have an affect on the value } of the whole expression `( c = getchar() )'. Interestingly enough, } the VAX 4.2bsd cc agrees with me, and produces (code to get value of } getchar() ommited, but it's in r0): } } L9998: } cvtlb r0,-1(fp) ; coercion and assignment to c as byte } cmpl r0,$-1 ; but comparison is int to int } jeql L36 ; break the loop iff same } } whilst the SUN 4.2 cc feels otherwise, and produces (getchar() value in d0): } } L2000001: } movb d0,a6@(-0x1) ; assignment to c } cmpb #-0x1,d0 ; comparison of a byte to a byte } jeq L23 ; break loop iff same } } Now while some might argue that the second interpretation is properly } conformant, and the first is brain-damaged (smile, gentle people), I } would argue that the first way of doing things is less likely to get } the poor programmer (myself, for instance) into trouble. I argue } that this is because in this context, the assignment is a side } effect, and isn't intended to `narrow' the value of the expression. } Just to point out where the logical extension of case two gets us, } what is the value of x in this fragment: } } float x; } int i; } } x = 2.0 + ( i = 3.5 ); } } I would say 5.5; others might say 5.0, it seems. But if I _wanted_ } 5.0, I would expect to write } } x = 2.0 + (int) ( i = 3.5 ); } } and I appeal to the principle of least astonishment for justification. Sir, In my copy of K&R's "The C Programming Language" the last line of section 2.10 titled "Assignment Operators and Expressions" states: "The type of an assignment expression is the type of the left oppernd" In "The C Programmers Handbook" [a Prentice Hall publication sanctioned by bell labs if it really matters] at the top of page #12 just under the title "ASSIGNMENT" is the following: NOTE -- The value of an assignment expression is the value of the left opperand _AFTER_ the assignment. It would seem obvious to me, even without these quotes as backup, that your vax is leading you down the garden path and you are happy to follow. The original questioner also must be questioned. K&R repeatedly and constantly state that in the expression (c = getchar()) c must be type int in order to preserve the EOF condidion because EOF must lie outside the range of any and all possible characters and that any value held by a variable of type char is a valid character. In your first code fragment c should be type int, and any opperations on c will be cast as approprate. In your statement that the assignment is, or should be, a secondary consideration to the value... The parens "(" ")" would say quite the contrary. As all math is done as longs and doubles under "C", at least according to the stndard, the type of an expression must come from somewhare. The precidence rules dont allow the expression without the parens, to return any value but 0 or 1 th the variable c. In your second code fragment the answer is 5.0. You dont need the cast to int because the declaration of i as int does that. The rule of least astonishment involves the comparison of explicit opperations to implicit, stating that the implicit should follow the explicit. That is, if you place every parened fraagment in an atonomus statment the values should remain unchanged. therefore: char c; while ((c = getchar()) != EOF) { /* Valid Opperations */ } Becomes: char c; c = getchar(); while (c != EOF) { /* Valid Opperations */; c = getchar (); } Which you may recognize, in form anyway, from pascal. By definition both these loops must behave exactly the same. By your argument the second fails but the first would opperate properly. With least astonishment in "C" this loop will never terminate, in either form, with c typed as char but it will function correctly with c typed as int becaues, as you know, type char cannot hold EOF but int can. Robert. Disclaimer: My mind is so fragmented by random excursions into a wilderness of abstractions and incipient ideas that the practical purposes of the moment are often submerged in my consciousness and I don't know what I'm doing. [my employers certainly have no idea]