Jump to page: 1 25  
Page
Thread overview
D and expression evaluation order.
Apr 26, 2007
Bruno Medeiros
Apr 26, 2007
Frits van Bommel
Apr 26, 2007
Bruno Medeiros
Apr 26, 2007
Luís Marques
Apr 26, 2007
Frits van Bommel
Apr 27, 2007
Bruno Medeiros
Apr 27, 2007
Frits van Bommel
Apr 27, 2007
James Dennett
Apr 26, 2007
Manfred Nowak
Apr 26, 2007
Luís Marques
Apr 26, 2007
Luís Marques
Apr 26, 2007
Walter Bright
Apr 26, 2007
Russell Lewis
Apr 26, 2007
Manfred Nowak
Apr 27, 2007
Russell Lewis
Apr 27, 2007
Sean Kelly
Apr 27, 2007
Russell Lewis
Apr 28, 2007
Bruno Medeiros
Apr 28, 2007
Sean Kelly
Apr 30, 2007
Bruno Medeiros
Apr 30, 2007
Daniel Keep
Apr 30, 2007
Jan Claeys
Apr 30, 2007
Sean Kelly
Apr 27, 2007
Manfred Nowak
Apr 26, 2007
Manfred Nowak
Apr 27, 2007
Walter Bright
Apr 27, 2007
Manfred Nowak
Apr 27, 2007
Walter Bright
Apr 27, 2007
Manfred Nowak
Apr 27, 2007
Bruno Medeiros
Apr 27, 2007
Russell Lewis
Apr 27, 2007
Manfred Nowak
Apr 30, 2007
Bruno Medeiros
Apr 30, 2007
Manfred Nowak
May 01, 2007
Bruno Medeiros
May 01, 2007
Manfred Nowak
May 01, 2007
Benji Smith
May 06, 2007
Bruno Medeiros
May 06, 2007
Daniel Keep
May 07, 2007
Manfred Nowak
Apr 27, 2007
janderson
April 26, 2007
As we know, in C/C++ there are a lot of cases where the order of
evaluation of an expression is undefined.

  i = i++;
  c = a + (a = b);
  func(++i, ++i);

D goes one step further by defining that any such behavior is illegal:
"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." in
http://www.digitalmars.com/d/expression.html .

That's nice, but why not go all the way, and actually define an
evaluation order for such expressions. There is nothing to lose, and it should be easy to implement. This is what Java does. For
example, the following (which I found recently in JDT's code) is
perfectly legal Java code:

  int length = array.length;
  ...
  System.arraycopy(array, 0, array = new IFoo[length + 1], 0, length);

because Java not only defines that the argument evaluation order is left
to right, but also that the arguments are bound to parameters as they
are evaluated (and not after all are evaluated).

The little details matter a lot.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
April 26, 2007
Bruno Medeiros wrote:
> As we know, in C/C++ there are a lot of cases where the order of
> evaluation of an expression is undefined.
> 
>   i = i++;
>   c = a + (a = b);
>   func(++i, ++i);
> 
> D goes one step further by defining that any such behavior is illegal:
> "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." in
> http://www.digitalmars.com/d/expression.html .

Actually, if I read that right it just says that the order of evaluation is undefined and should not be relied upon. Just like C/C++.

> That's nice, but why not go all the way, and actually define an
> evaluation order for such expressions. There is nothing to lose, and it should be easy to implement. This is what Java does. For
> example, the following (which I found recently in JDT's code) is
> perfectly legal Java code:
> 
>   int length = array.length;
>   ...
>   System.arraycopy(array, 0, array = new IFoo[length + 1], 0, length);
> 
> because Java not only defines that the argument evaluation order is left
> to right, but also that the arguments are bound to parameters as they
> are evaluated (and not after all are evaluated).
> 
> The little details matter a lot.

Unspecified evaluation order is an optimization opportunity.
For instance, the most efficient parameter evaluation order can be dependent on the calling convention, which is platform-dependent. For instance on x86 and amd64 platforms the most efficient evaluation order can very well be to evaluate right-to-left, since typical calling conventions specify the last argument is to be pushed onto the stack first[1]. (There are good reasons for that, mostly to do with varargs)
DMD's extern(D) (i.e. the default) calling convention and GDC's amd64 calling convention are a slight variation on that, passing some arguments in a register if possible. It may for that reason be more efficient to evaluate those in another order so that those registers can be used in evaluation of other arguments.


[1] Though on amd64 the first few arguments are typically passed in registers, and DMD by default passes one argument in a register as well, so the stack may not be used if there are few arguments.
April 26, 2007
Bruno Medeiros wrote

> define an evaluation order for such expressions

- if a coder wants to define an order, she/he is free to use an
appropriate sequence of assignments
- if there is a predefined order, then
-- that predefined order must be learned by everyone
-- for every deviation of that order the appropriate sequence of
assignments must be coded anyway

-manfred
April 26, 2007
Manfred Nowak wrote:
> - if a coder wants to define an order, she/he is free to use an appropriate sequence of assignments
> - if there is a predefined order, then
> -- that predefined order must be learned by everyone
> -- for every deviation of that order the appropriate sequence of assignments must be coded anyway

If there weren't performance issues I don't think there would be any reason for the order not to be fixed. If someone knew the order they could rely on it. If they didn't they could also order the assignments. I don't think average programmers using Java even notice they learned the evaluation order, they just do it intuitively.

For Java, the safety is more important. For D performance is.

--
Luís
April 26, 2007
Manfred Nowak wrote:
> - if a coder wants to define an order, she/he is free to use an appropriate sequence of assignments
> - if there is a predefined order, then
> -- that predefined order must be learned by everyone
> -- for every deviation of that order the appropriate sequence of assignments must be coded anyway

If there weren't performance issues I don't think there would be any
reason for the order not to be fixed. If someone knew the order they
could rely on it. If they didn't they could also order the assignments.
I don't think average programmers using Java even notice they learned
the evaluation order, they just do it intuitively.

For Java, the safety is more important. For D performance is.

--
Luís
April 26, 2007
Bruno Medeiros wrote:
> That's nice, but why not go all the way, and actually define an
> evaluation order for such expressions.

I want to do that eventually, but it isn't easy to do. (There are also issues with making it work with a C back end, where the C optimizer reorders things according to what is legal C.)
April 26, 2007
Walter Bright wrote:
> Bruno Medeiros wrote:
>> That's nice, but why not go all the way, and actually define an
>> evaluation order for such expressions.
> 
> I want to do that eventually, but it isn't easy to do. (There are also issues with making it work with a C back end, where the C optimizer reorders things according to what is legal C.)

To me, this sounds like a slam-dunk argument for never defining an evaluation order.  Why prevent optimizers from doing all that they can conceive of?  IMHO, the only places where you want to define evaluation order is when it makes the program clearer, and the examples given are (again, my opinion) examples of bad coding style.  If you want to do something complex, then code the steps in different statements; then it's totally clear what you're trying to do - to both the compiler *and* the guy maintaining your code 10 years from now.

Russ
April 26, 2007
Frits van Bommel wrote:
> Bruno Medeiros wrote:
>> As we know, in C/C++ there are a lot of cases where the order of
>> evaluation of an expression is undefined.
>>
>>   i = i++;
>>   c = a + (a = b);
>>   func(++i, ++i);
>>
>> D goes one step further by defining that any such behavior is illegal:
>> "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." in
>> http://www.digitalmars.com/d/expression.html .
> 
> Actually, if I read that right it just says that the order of evaluation is undefined and should not be relied upon. Just like C/C++.
> 

Read the paragraph ahead in the doc. In D that is considered a language(i.e. compile) error and so the compiler can issue an error. In C/C++ it is merely undefined program behavior, the code remains compilable.

>> That's nice, but why not go all the way, and actually define an
>> evaluation order for such expressions. There is nothing to lose, and it should be easy to implement. This is what Java does. For
>> example, the following (which I found recently in JDT's code) is
>> perfectly legal Java code:
>>
>>   int length = array.length;
>>   ...
>>   System.arraycopy(array, 0, array = new IFoo[length + 1], 0, length);
>>
>> because Java not only defines that the argument evaluation order is left
>> to right, but also that the arguments are bound to parameters as they
>> are evaluated (and not after all are evaluated).
>>
>> The little details matter a lot.
> 
> Unspecified evaluation order is an optimization opportunity.
> For instance, the most efficient parameter evaluation order can be dependent on the calling convention, which is platform-dependent. For instance on x86 and amd64 platforms the most efficient evaluation order can very well be to evaluate right-to-left, since typical calling conventions specify the last argument is to be pushed onto the stack first[1]. (There are good reasons for that, mostly to do with varargs)
> DMD's extern(D) (i.e. the default) calling convention and GDC's amd64 calling convention are a slight variation on that, passing some arguments in a register if possible. It may for that reason be more efficient to evaluate those in another order so that those registers can be used in evaluation of other arguments.
> 
> 

In that case, it is possible for the compiler to detect if the evaluation order matters, and if it doesn't (currently the only allowed situation in D), it can push the arguments in any order it pleases him.

Even if that wasn't possible, I'm not sure that with modern CPU technology, right-to-left calling conventions (last argument on top) would be any slower to call with an left-to-right eval order, than with an undefined order. Then again, I'm no Assembler or CPU optimization expert, so correct if I'm wrong.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
April 26, 2007
Bruno Medeiros wrote:
> In that case, it is possible for the compiler to detect if the evaluation order matters, and if it doesn't (currently the only allowed situation in D), it can push the arguments in any order it pleases him.

The compiler can only detect some cases, kind of like constant folding, but it might aliviate many cases. Inter-module flow analysis would help here (coming soon with GCC, weee!)

--
Luís
April 26, 2007
Russell Lewis wrote

> Why prevent optimizers from doing all that they can conceive of?

This is not an issue, because the requirement is to define an order for those cases only, where currently evaluation order matters. In all other cases the compiler is free to choose the optimum the same way it currently does.

-manfred
« First   ‹ Prev
1 2 3 4 5