www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Evaluation Order

reply Sean Kelly <sean f4.ca> writes:
This bit from the spec has me concerned:

Unless otherwise specified, the implementation is free to evaluate the 
components of an expression in any order. It is an error to depend on 
order of evaluation when it is not specified.

C++ has well-defined evaluation rules, and this almost seems necessary for complex mathematical expressions. But aside from logical operators and the comma operator I can't find any information on eevaluation order in the D spec. For example, this expression: int x = 5 * 4 / 3; has a well-defined result in C/C++, but does it in D? Or should perenthesis always be used? Sean
May 29 2004
next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Sean Kelly wrote:
 This bit from the spec has me concerned:
 
  >Unless otherwise specified, the implementation is free to evaluate the 
  >components of an expression in any order. It is an error to depend on 
  >order of evaluation when it is not specified.
     
 C++ has well-defined evaluation rules, and this almost seems necessary 
 for complex mathematical expressions.  But aside from logical operators 
 and the comma operator I can't find any information on eevaluation order 
 in the D spec.  For example, this expression:
 
 int x = 5 * 4 / 3;
 
 has a well-defined result in C/C++, but does it in D?  Or should 
 perenthesis always be used?

The result is well defined, but the order in which the terms are evaluated is not. That part of the spec pertains to something like this: int x = (5 * 4) + (3 / 2); D reserves the right to compute either the multiply or divide first. Obviously, since the addition needs the result of both, it is going to be last. -- andy
May 29 2004
parent Sean Kelly <sean f4.ca> writes:
Andy Friesen wrote:
 The result is well defined, but the order in which the terms are 
 evaluated is not.  That part of the spec pertains to something like this:
 
 int x = (5 * 4) + (3 / 2);
 
 D reserves the right to compute either the multiply or divide first. 
 Obviously, since the addition needs the result of both, it is going to 
 be last.

Ah, that's what I figured but the attached examples had me wondering. So D follows standard operator precedence rules and evaluation order for all scenarios I care about :) Sean
May 29 2004
prev sibling next sibling parent reply "Bent Rasmussen" <exo bent-rasmussen.info> writes:
I'd guess this has something to do with side-effects. If you have a boolean
expression like

a || b

and both sides exhibit side-effects, you can't rely on any order of
evaluation to determine which side-effect takes place first. Perhaps you
can't even be sure that both sides of the above expression will be evaluated
if any of the sides evaluate to true. I don't know though.

The specification has an example where the order of evaluation affects the
value of the expression

    c = a + (a = b)

So here the order of evaluation affects c which it would seem easy for the
compiler to detect. Of course its easy to construct difficult cases.

In such a simple example it would seem no problem to detect order of
evaluation dependency but of course its easy to construct an example where
its much harder to detect that evaluation order affects the result. It seems
like a good principle for stuff like assertions that use boolean
expressions.

Further examination of the spec says

"The OrOr expression evaluates its left operand. If the left operand,
converted to type bool, evaluates to true, then the right operand is not
evaluated."

It makes sense and of course if you expected the right operand to evaluate
because it exhibits some side-effect then you'll be disappointed and that's
how it should be it seems to me. I think Eiffel has allways evaluates the
full boolean expression except if you use "and then" or "or else".
May 29 2004
parent Sean Kelly <sean f4.ca> writes:
Bent Rasmussen wrote:

 I'd guess this has something to do with side-effects. If you have a boolean
 expression like
 
 a || b
 
 and both sides exhibit side-effects, you can't rely on any order of
 evaluation to determine which side-effect takes place first. Perhaps you
 can't even be sure that both sides of the above expression will be evaluated
 if any of the sides evaluate to true. I don't know though.

That was my guess too, but "expressions" was sufficiently vage that I wanted to ask.
 The specification has an example where the order of evaluation affects the
 value of the expression
 
     c = a + (a = b)

This is the example that threw me. I had thought that the parenthesis would force the assignment to occur before the addition, even though assignments are typically fairly low on the precedence tree.
 Further examination of the spec says
 
 "The OrOr expression evaluates its left operand. If the left operand,
 converted to type bool, evaluates to true, then the right operand is not
 evaluated."

This is required for short-circuit evaluation. The AndAnd bit has a similar clause. But they're just about the only expressions that mention evaluation, so I was left wondering. (for the record, the comma operator and the logical if operators also mention evaluation order).
 It makes sense and of course if you expected the right operand to evaluate
 because it exhibits some side-effect then you'll be disappointed and that's
 how it should be it seems to me. I think Eiffel has allways evaluates the
 full boolean expression except if you use "and then" or "or else".

Yup. Some of the .NET languages are like this also. Frankly, it drives me crazy :) I guess I've just become accustomed to the C/C++ method. Sean
May 29 2004
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:c9ase5$a2c$1 digitaldaemon.com...
 This bit from the spec has me concerned:

  >Unless otherwise specified, the implementation is free to evaluate the
  >components of an expression in any order. It is an error to depend on
  >order of evaluation when it is not specified.

 C++ has well-defined evaluation rules, and this almost seems necessary
 for complex mathematical expressions.  But aside from logical operators
 and the comma operator I can't find any information on eevaluation order
 in the D spec.  For example, this expression:

 int x = 5 * 4 / 3;

 has a well-defined result in C/C++, but does it in D?  Or should
 perenthesis always be used?

There are two different things going on here - one is evaluation order, and the other is the operator precedence, associativity and commutativity rules. The latter are well defined, in D as well as C++, and in your example evaluates as (5*4)/3. The former are not, in D and C++. For example: (a + b) * (c + d) which is evaluated first, (a + b) or (c + d)? The specification leaves this up to the compiler in both languages.
May 29 2004
parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <c9blde$1bs0$3 digitaldaemon.com>, Walter says...

There are two different things going on here - one is evaluation order, and
the other is the operator precedence, associativity and commutativity rules.
The latter are well defined, in D as well as C++,

Is precedence order defined the same way in D that it is in C? I ask because I think C got it wrong, and I'd hate to think we were copying the flaws as well as the good bits. I always thought it a mistake that the precedence of &, | and ^ was defined such that:
       if (a & 1 == 1)

gives (1 == 1) precedence over (a & 1). It's not intuitive in C. C++ copied it, and it's not intuitive in C++. I think even Java copied it, and it's not intuitive there either. Believe it or not, I think BASIC got this right! I would prefer precedence order to be: << >> & ^ | * / % + - < > <= >= etc == != && || (but I guess it would break too much to change that now). Arcane Jill
May 29 2004
next sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Arcane Jill" <Arcane_member pathlink.com> wrote in message
news:c9bssf$1mld$1 digitaldaemon.com...
 In article <c9blde$1bs0$3 digitaldaemon.com>, Walter says...
There are two different things going on here - one is evaluation order,


the other is the operator precedence, associativity and commutativity


The latter are well defined, in D as well as C++,


Yes.
 I ask because I think C got it wrong, and I'd hate to think we were

 flaws as well as the good bits.

 I always thought it a mistake that the precedence of &, | and ^ was

 that:

       if (a & 1 == 1)

gives (1 == 1) precedence over (a & 1). It's not intuitive in C. C++

 and it's not intuitive in C++. I think even Java copied it, and it's not
 intuitive there either. Believe it or not, I think BASIC got this right!

 I would prefer precedence order to be:

 << >>
 & ^ |
 * / %
 + -
 < > <= >= etc
 == !=
 && ||

 (but I guess it would break too much to change that now).

Since D is designed to appeal to C/C++ programmers, changing the precedence order that, for good or ill, we're all used to would introduce subtle bugs. I'd prefer to change only things that would yield obvious errors if done using the C/C++ semantics.
May 29 2004
parent reply Juan C <Juan_member pathlink.com> writes:
Since D is designed to appeal to C/C++ programmers, changing the precedence
order that, for good or ill, we're all used to would introduce subtle bugs.
I'd prefer to change only things that would yield obvious errors if done
using the C/C++ semantics.

D would appeal more to _this_ C programmer if _all_ the flaws of C/C++ were fixed. On the other hand, I believe that the last time this particular concern was raised, Walter was able to convince me that this was the _correct_ order. However, I seem to recall that my agreement required that boolean not be implicitly cast to or from other types.
May 30 2004
parent "Walter" <newshound digitalmars.com> writes:
"Juan C" <Juan_member pathlink.com> wrote in message
news:c9ctl4$sg$1 digitaldaemon.com...
 D would appeal more to _this_ C programmer if _all_ the flaws of C/C++

 fixed.

The trouble with that is there is little agreement on what _all_ the flaws are!
May 30 2004
prev sibling parent reply Kevin Bealer <Kevin_member pathlink.com> writes:
In article <c9bssf$1mld$1 digitaldaemon.com>, Arcane Jill says...
In article <c9blde$1bs0$3 digitaldaemon.com>, Walter says...

There are two different things going on here - one is evaluation order, and
the other is the operator precedence, associativity and commutativity rules.
The latter are well defined, in D as well as C++,

Is precedence order defined the same way in D that it is in C? I ask because I think C got it wrong, and I'd hate to think we were copying the flaws as well as the good bits. I always thought it a mistake that the precedence of &, | and ^ was defined such that:
       if (a & 1 == 1)

gives (1 == 1) precedence over (a & 1). It's not intuitive in C. C++ copied it, and it's not intuitive in C++. I think even Java copied it, and it's not intuitive there either. Believe it or not, I think BASIC got this right! I would prefer precedence order to be: << >> & ^ | * / % + - < > <= >= etc == != && || (but I guess it would break too much to change that now). Arcane Jill

I remember that "*" is before "+", comparisons (<, ==) are before "&&" and "||", and maybe one or two others. For almost everything else I use the parens, for readability and safety. I don't expect the compiler to get it wrong, but I know that I will, and I hate debugging this stuff: I'd rather be hunting orc than squirrel if you get my meaning. Incidentally, what are "&&" and "||" supposed to return? I think at one point I read that || returns the first argument that is true, or the second argument, but I tried it and it didn't work in whatever language I was using. It would be useful if you could say: (return x || y || 100), but I don't know if that makes sense in the bigger picture. Kevin
May 30 2004
next sibling parent reply "Vathix" <vathixSpamFix dprogramming.com> writes:
"Kevin Bealer" <Kevin_member pathlink.com> wrote in message
news:c9c6uu$24ul$1 digitaldaemon.com...
   ...
 Incidentally, what are "&&" and "||" supposed to return?  I think at one

 read that || returns the first argument that is true, or the second

 but I tried it and it didn't work in whatever language I was using.  It

 useful if you could say: (return x || y || 100), but I don't know if that

 sense in the bigger picture.

JavaScript does that with ||, like alert("foo" || "bar"); displays "foo". I've never used it in real code, but it is interesting. C style languages just return 0 for false and 1 for true; which is depended on in some cases. Changing it would cause those "subtle bugs" I would think.
May 30 2004
next sibling parent Juan c <Juan_member pathlink.com> writes:
JavaScript does that with ||, like alert("foo" || "bar"); displays "foo".
I've never used it in real code, but it is interesting. C style languages
just return 0 for false and 1 for true; which is depended on in some cases.
Changing it would cause those "subtle bugs" I would think.

Don't they return true or false?
May 30 2004
prev sibling parent Kevin Bealer <Kevin_member pathlink.com> writes:
In article <c9cpc5$2si0$1 digitaldaemon.com>, Vathix says...
"Kevin Bealer" <Kevin_member pathlink.com> wrote in message
news:c9c6uu$24ul$1 digitaldaemon.com...
   ...
 Incidentally, what are "&&" and "||" supposed to return?  I think at one

 read that || returns the first argument that is true, or the second

 but I tried it and it didn't work in whatever language I was using.  It

 useful if you could say: (return x || y || 100), but I don't know if that

 sense in the bigger picture.

JavaScript does that with ||, like alert("foo" || "bar"); displays "foo". I've never used it in real code, but it is interesting. C style languages just return 0 for false and 1 for true; which is depended on in some cases. Changing it would cause those "subtle bugs" I would think.

The purpose of this, conceptually, is that there are a lot of times in C, at least, where you might like to do something like this: void bar(int x, int y, char * optional_arg) { char * baz = optional_arg || getenv("BAR_BAZ") || "<default>"; .. } Since C uses pointers for everything, and a non-null pointer is true, this allows you to pick the first "value source" that is non-null. If you take advantage of this, you can program very readable code: a sequence of "||", read as "or else try", is very understandable compared to an if-then-else pile. It shouldn't hurt semantics either: work out the above and you can see that if "baz" is tested as a boolean, taking the first "nonzero" value, or the last value in the chain (the second, in the 2-argument case) will work. Maybe none of this is true in D. I don't expect this would work in the presence of objects, since boolean bitmath and operator overloading probably clobber it. It's not a feature request, just wondered what I was remembering it from. Kevin
May 31 2004
prev sibling parent J Anderson <REMOVEanderson badmama.com.au> writes:
Kevin Bealer wrote:

In article <c9bssf$1mld$1 digitaldaemon.com>, Arcane Jill says...
  

In article <c9blde$1bs0$3 digitaldaemon.com>, Walter says...

    

There are two different things going on here - one is evaluation order, and
the other is the operator precedence, associativity and commutativity rules.
The latter are well defined, in D as well as C++,
      

I ask because I think C got it wrong, and I'd hate to think we were copying the flaws as well as the good bits. I always thought it a mistake that the precedence of &, | and ^ was defined such that:
      if (a & 1 == 1)
      

and it's not intuitive in C++. I think even Java copied it, and it's not intuitive there either. Believe it or not, I think BASIC got this right! I would prefer precedence order to be: << >> & ^ | * / % + - < > <= >= etc == != && || (but I guess it would break too much to change that now). Arcane Jill

I remember that "*" is before "+", comparisons (<, ==) are before "&&" and "||", and maybe one or two others. For almost everything else I use the parens, for readability and safety. I don't expect the compiler to get it wrong, but I know that I will, and I hate debugging this stuff: I'd rather be hunting orc than squirrel if you get my meaning. Incidentally, what are "&&" and "||" supposed to return? I think at one point I read that || returns the first argument that is true, or the second argument, but I tried it and it didn't work in whatever language I was using. It would be useful if you could say: (return x || y || 100), but I don't know if that makes sense in the bigger picture. Kevin

You mean? return (x || y || 100); Which logically will always return true because anything other then zero = true; -- -Anderson: http://badmama.com.au/~anderson/
May 30 2004