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]