www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Evaluation order

reply bearophile <bearophileHUGS lycos.com> writes:
(I discuss such topics here because I don't know where else I can)

I have seen a recent change:
http://dsource.org/projects/dmd/changeset/399

I guess it's something related to specifying an evaluation order in D in
function calls like bar() of main():

import std.stdio: writeln;
import std.string: format;

class Obj {
    int x;
    this(int xx) { x = xx; }
    string member() { return format("member ", x); }
}

Obj foo() {
    return new Obj(2);
}

void bar(string s, Obj o2) {
    writeln("bar ", s, " ", o2.x);
}

void main() {
    Obj o = new Obj(1);
    bar(o.member(), o=foo());
}

C specifications do not define the order of evaluation for function arguments.
It can be left-to-right, right-to-left or anything else and is unspecified.
Thus any code which relies on this order of evaluation is not portable.

D can solve this problem as I think Java has done, just specifying it, and
forcing the compiler to produce hypothetically a bit less efficient code in
some situations.

Another strategy to solve this problem that's possible in D (and not possible
in C) is to allow only pure expressions inside function calls. So in a function
call you can put pure expressions like x+5 or calls to pure functions. And then
the D compiler is free to leave unspecified the order of evaluation of function
arguments.

Bye,
bearophile
Feb 24 2010
parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
bearophile wrote:

 C specifications do not define the order of evaluation for function
 arguments. It can be left-to-right, right-to-left or anything else and is
 unspecified. Thus any code which relies on this order of evaluation is not
 portable.
 
 D can solve this problem as I think Java has done, just specifying it, and
 forcing the compiler to produce hypothetically a bit less efficient code
 in some situations.
 
 Another strategy to solve this problem that's possible in D (and not
 possible in C) is to allow only pure expressions inside function calls. So
 in a function call you can put pure expressions like x+5 or calls to pure
 functions. And then the D compiler is free to leave unspecified the order
 of evaluation of function arguments.

I would prefer that the evaluation order be officially specified as non-deterministic. That is, the standard guarantees that the observable behavior be equivalent to some sequential order of evaluation. For example: void f() {} f(x = 1, x = 2); assert(x == 1 || x == 2); It's the same as what C does, just more formally defined. The compiler is free to choose the most efficient implementation that satisfies the contract. This is because to me, any asymmetric choice of evaluation order would be arbitrary and wrong. What's so special about left-to-right? -- Michiel Helvensteijn
Feb 24 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michiel Helvensteijn wrote:
 This is because to me, any asymmetric choice of evaluation order would be
 arbitrary and wrong. What's so special about left-to-right?

Arbitrary, yes. Wrong? no - specifying it removes another source of potential user bugs. Left-to-right is natural because that's the way we read things.
Feb 24 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 Arbitrary, yes. Wrong? no - specifying it removes another source of 
 potential user bugs. Left-to-right is natural because that's the way we 
 read things.

If the language accepts only pure expressions inside function calls then it keeps being safe, despite using the most efficient order the compiler finds. Bye, bearophile
Feb 24 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 Walter Bright:
 Arbitrary, yes. Wrong? no - specifying it removes another source of
  potential user bugs. Left-to-right is natural because that's the
 way we read things.

If the language accepts only pure expressions inside function calls then it keeps being safe, despite using the most efficient order the compiler finds.

All compiler behavior is based on what the observer sees. If the compiler can rearrange things in a manner that the observer cannot detect, then the rearrangement is allowed.
Feb 24 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 All compiler behavior is based on what the observer sees. If the 
 compiler can rearrange things in a manner that the observer cannot 
 detect, then the rearrangement is allowed.

OK. But if the language turns putting impure expressions inside a function call into a compile time error, allowing only pure expressions inside function calls, then the compiler can always be free to rearrange those expressions, and there's both no performance penalty and the programmer can be certain there is no performance penalty. I guess you are not interested in this idea. Bye, bearophile
Feb 24 2010
parent Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 Walter Bright:
 All compiler behavior is based on what the observer sees. If the 
 compiler can rearrange things in a manner that the observer cannot
  detect, then the rearrangement is allowed.

OK. But if the language turns putting impure expressions inside a function call into a compile time error, allowing only pure expressions inside function calls, then the compiler can always be free to rearrange those expressions, and there's both no performance penalty and the programmer can be certain there is no performance penalty. I guess you are not interested in this idea.

I agree I'm not interested in making impure expressions illegal. But I was just pointing out that the compiler optimizer *already* relies on knowing about side effects when reordering code. It's central to any flow analysis optimization.
Feb 24 2010
prev sibling parent Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Walter Bright wrote:

 This is because to me, any asymmetric choice of evaluation order would be
 arbitrary and wrong. What's so special about left-to-right?

Arbitrary, yes. Wrong? no - specifying it removes another source of potential user bugs. Left-to-right is natural because that's the way we read things.

I'm sure you are aware that entire cultures read things right-to-left. Anyway, don't think I don't see your reasoning. I can argue your point: * Even though both are equally well-defined behavioral contracts, many people will understand a fixed sequential order better than non-deterministic choice, so might cause more bugs in the latter case. * D already contains English keywords and English libraries. It's already dominantly western, so left-to-right won't be unexpected. I just have this quest for a beautiful and elegant programming language. In such a language, the order of side-effects should not matter in any operation (not just function calls). Operators that are commutative in math (and, or, +, *) should be commutative in the programming language too, regardless of side-effects and short-circuiting (which would still be possible, ask me how). But I understand why D places more value on practicality than beauty and elegance. -- Michiel Helvensteijn
Feb 24 2010