[comp.lang.c] Order of evaluation

john@viper.UUCP (03/04/87)

  I made an incorrect statement a few days ago in this newsgroup about the 
order of evaluation of a series of additions where parens were included.
The message I was disagreeing with stated that the parens have no effect
on the structure of the evaluation tree generated.

  Since then, I've received a few messages pointing out references in K&R
which explicitly state that the elements in a series of additions (or
multiplications) may freely be reordered to occur in any order by the
compiler.

  I sit corrected, but I still feel that the standard should have rules
which will allow a programmer to -know- the exact order of evaluation for
any equation.  I know this is not likely for the sole reason that there
are too many different compilers already existing that do the ordering in
far too many different ways....  I still feel that this is a significant
failing in the language definition and would like to see a change.

--- 
John Stanley (john@viper.UUCP)
Software Consultant - DynaSoft Systems
UUCP: ...{amdahl,ihnp4,rutgers}!{meccts,dayton}!viper!john

tps@sdchem.UUCP (Tom Stockfisch) (03/07/87)

In article <616@viper.UUCP> john@viper.UUCP (John Stanley) writes:

>... but I still feel that the standard should have rules
>which will allow a programmer to -know- the exact order of evaluation for
>any equation.  I know this is not likely for the sole reason that there
>are too many different compilers already existing that do the ordering in
>far too many different ways....  I still feel that this is a significant
>failing in the language definition and would like to see a change.
>John Stanley (john@viper.UUCP)

I feel this is a significant *feature* of the language.  This issue has
been discussed recently, but I would like to summarize the pluses of
allowing expression rearrangement.  Most of the ideas below were contributed
by others, and thats all the more specific credit I can give since I didn't save
any of the postings.

1.  Most of the time, unless you are writing for one particular machine,
    the compiler knows better in what order to perform operations, since
    that order is machine-dependent.  An important feature of C is that
    not only is the correctness of a program portable among many machines,
    but usually its efficiency as well.  The local compiler chooses the
    method best for the local machine to implement your algorithm.

2.  You can write expressions in a way that best documents them for and
    explains them to other human readers.

3.  If you have complex multiple side effects in the same expression,
    you deserve what you get.

4.  There are two mechanisms available for when you really need to know
    the order:
	1)  Separate the expression into two statements.
	2)  Use the unary plus operator (when you get your ANSI compiler).

5.  If you want everything evaluated strictly from left to right, your
    thinking is too linear.


What are you are proposing is to remove an important feature that can't
be gotten at any other way.  Reliable execution order can be forced when
you really need it.  If we drop the rearrangement feature there is no
way to tell the compiler "I don't care how you do it, just get it done,
hopefully using the methods best for the machine on which you exist."
C currently provides both features, and since the "I don't care how..."
one is by far the more common one, it is very appropriately the default.

Who wants a language with fewer features (besides Ada users)?
Finally, if you were to remove this feature, there
    would be no way to get it back.  

|| Tom Stockfisch, UCSD Chemistry	tps%chem@sdcsvax.UCSD

flaps@utcsri.UUCP (Alan J Rosenthal) (03/08/87)

In article <616@viper.UUCP> john@viper.UUCP (John Stanley) writes:
>I still feel that the standard should have rules
>which will allow a programmer to -know- the exact order of evaluation for
>any equation.

It does.. use temporaries.  For example, if you want the sum a+b+c evaluated
in the order implied by (a+b)+c, simply write two statements, the first of
which is t=a+b; and the second of which contains the expression t+c.  (If you
have a REALLY good optimizer it's possible that this temporary variable will be
optimized out completely.  In any case, the redundant store/load will probably
be optimized out.)

>I know this is not likely for the sole reason that there
>are too many different compilers already existing that do the ordering in
>far too many different ways.

Also for the reason that there is quite likely a different best order for
different machines, so the compilers should be free to implement the best
order for their machine.

-- 

Alan J Rosenthal

UUCP: {backbone}!seismo!mnetor!utgpu!flaps, ubc-vision!utai!utgpu!flaps,
      or utzoo!utgpu!flaps (among other possibilities)
ARPA: flaps@csri.toronto.edu
CSNET: flaps@toronto
BITNET: flaps at utorgpu

chris@mimsy.UUCP (03/25/87)

In article <739@xanth.UUCP> kent@xanth.UUCP (Kent Paul Dolan) writes:
>... but C was an ugly language to begin with, because so much of
>it doesn't parse the way it reads, due to _bizarre_ precedence results.

Aside from the results of chongo's contests, I find most C code
quite readable.  The trouble areas are unusual declarations and
`&' and `|' precedence:

	char *(*p[3])();
	...
	if (a & 1 == 0)		/* is not what you expected */

The solution to the latter, of course, is (dramatic music) to Put
In Many Many Parentheses.

>Adding the unary plus, which, to anyone taught mathematics,
>is a no-op, and making that the way to control the order of
>evaluation, just makes an ugly language uglier.

While it is a bit of a kludge, the fact that someone has written
an explicit no-op should give you a hint that something special is
going on.

>ANSI should have mandated respecting parentheses for evaluation
>order, so that code executes the way it reads.

I do not agree.

>This would break _no_ code,

True enough.

>and would let programmers' intuition be of some use ....

Whose intuition?  Certainly not mine.  I expect the compiler to
rip my parentheses to shreds.  I confess to having written some
floating point code in the past, aye, even in FORTRAN.  I used
multiple lines of statments to control evaluation order---even in
FORTRAN, and even before I knew any other language except BASIC.
(A humble start indeed!)

	#define input() \
		((env->c = getc(fin)) == '\n' ? \
		 (env->lineno++, env->c) : env->c)
	#define output(c) \
		(putc(c, env->fout), ferror(env->fout) ? ioerr() : 0)
	output(input())

produces

	((--(env->fout)->_cnt>=0?
	(int)(*(unsigned char*)(env->fout)->_ptr++=(((env->c=(--(fin)->_cnt>=0?
	(int)(*(unsigned char*)(fin)->_ptr++):_filbuf(fin)))=='\n'?
	(env->lineno++,env->c):env->c))):
	(((env->fout)->_flag&0200)&&-(env->fout)->_cnt<(env->fout)->_bufsiz?
	((*(env->fout)->_ptr=(((env->c=(--(fin)->_cnt>=0?
	(int)(*(unsigned char*)(fin)->_ptr++):_filbuf(fin)))=='\n'?
	(env->lineno++,env->c):env->c)))!='\n'?
	(int)(*(unsigned char*)(env->fout)->_ptr++):
	_flsbuf(*(unsigned char*)(env->fout)->_ptr,env->fout)):
	_flsbuf((unsigned char)(((env->c=(--(fin)->_cnt>=0?
	(int)(*(unsigned char*)(fin)->_ptr++):_filbuf(fin)))=='\n'?
	(env->lineno++,env->c):env->c)),env->fout))),
	(((env->fout)->_flag&040)!=0)?ioerr():0)

Ahh, lovely parentheses.  :-)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!mimsy!chris	ARPA/CSNet:	chris@mimsy.umd.edu

mouse@mcgill-vision.UUCP (der Mouse) (08/20/89)

In article <1989Aug9.094742.20000@gdt.bath.ac.uk>, exspes@gdr.bath.ac.uk (P E Smee) writes:

> (Although, being paranoid, I'd also suggest that the person writing
> a/b/c/d/e should inject lots of ()s to indicate that the ordering is
> really desired.  I tend to parenthesize everything :-)  Goes without
> saying that I strongly feel that languages should honor any
> order-of-evaluation requirements which the programmer specifies using
> parens.

I agree.  The problem is telling order-of-evaluation-requirements
parens from override-operator-precedence parens.  A high percentage
(most?) of the parentheses I use, for example, are either required
syntax (as in a while loop), which don't enter into this discussion, or
needed not because order of evaluation is important but to override
default operator precedence and associativity rules.

Then there are macros.

#define islower(c) (__ctypes[(c)+1]&__CTYPE_LOWER)

#define TABLE_FOR(c) (islower(c)?ltab:utab)

....

a_table = TABLE_FOR('a'+letindex);

(Let's ignore the ASCII-dependent nature of that for the moment.)  I
would be most disappointed in any compiler that failed to
constant-merge the 'a' and the 1 simply because the expanded text,
which would read something like

a_table = ((__ctypes[('a'+letindex)+1]&__CTYPE_LOWER)?ltab:utab);

happens to have a pair of parens which contain the 'a' but not the 1,
thereby prohibiting rearrangement to bring the 'a' and 1 together.

Yet if we omit that pair of parens in the definition of islower, it
then loses big if we write, for example,

islower(usec1?c1:c2)

which would then expand to

(__ctypes[usec1?c1:c2+1]&__CTYPE_LOWER)

...oops.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

(Curious.  Put "islower" next to "isupper" and it reads one way; put it
next to "jslower" and "kslower" and it reads entirely differently. :-)