www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D and expression evaluation order.

reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
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
Apr 26 2007
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
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.
Apr 26 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
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
Apr 26 2007
next sibling parent =?UTF-8?B?THXDrXMgTWFycXVlcw==?= <luismarques+spam gmail.com> writes:
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
Apr 26 2007
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Bruno Medeiros wrote:
 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.
IIRC[1] the C++ standard includes "causes a compile error" as one of the possible consequences of undefined behavior. I'm not sure about C. [1] I've been staying away from C++ since I started using D, so this is by no means a given... [snip]
 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)
[snip]
 
 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.
<nitpick> Actually, if you check the spec it says the compiler is allowed to issue an error if it detects the _result_ of the expression depends on evaluation order. It doesn't seem to mention side-effects at all, so evaluation order is technically allowed to matter (though it's still an error to _depend_ on it). Well, unless you count side-effects as part of the "result" of an expression... </nitpick>
 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.
Nor am I, but I've inspected a lot of the assembly code generated for my programs and often the DMD and GDC optimizers apparently decided to evaluate (roughly) right-to-left...
Apr 26 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Frits van Bommel wrote:
 Bruno Medeiros wrote:
 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.
IIRC[1] the C++ standard includes "causes a compile error" as one of the possible consequences of undefined behavior. I'm not sure about C. [1] I've been staying away from C++ since I started using D, so this is by no means a given...
I haven't read about C++ in detail, only C. But in both cases (and sometimes here in the NG too) I often see the documents call "undefined behavior" to thing they should call errors. They refer to these concepts almost interchangeably, whereas they are not. They overlap a lot but they are not the same, there is a subtle difference. Dereferencing a trash pointer, for example, *is* an error. It *causes* undefined behavior, but it *is not* merely undefined behavior: it *can crash* your program. On the other hand if do: func(i++, i++); where func simply prints prints its arguments, I will have undefined program behavior, but no program error : that code *can not ever* crash the program. (altough it is still likely a *conceptual* error) This is a minor nitpick, since in practice both should be equally avoided, but that subtle difference is still there.
 [snip]
 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)
[snip]
 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.
<nitpick> Actually, if you check the spec it says the compiler is allowed to issue an error if it detects the _result_ of the expression depends on evaluation order. It doesn't seem to mention side-effects at all, so evaluation order is technically allowed to matter (though it's still an error to _depend_ on it). Well, unless you count side-effects as part of the "result" of an expression... </nitpick>
To "depend on the evaluation order" is to have the evaluation order matter. :) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 27 2007
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Bruno Medeiros wrote:
 Frits van Bommel wrote:
 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.
<nitpick> Actually, if you check the spec it says the compiler is allowed to issue an error if it detects the _result_ of the expression depends on evaluation order. It doesn't seem to mention side-effects at all, so evaluation order is technically allowed to matter (though it's still an error to _depend_ on it). Well, unless you count side-effects as part of the "result" of an expression... </nitpick>
To "depend on the evaluation order" is to have the evaluation order matter. :)
Yes, if you depend on it then it indeed matters. But the other way around is not necessarily true; I think you can have a program where evaluation order matters (e.g. different orders produce different output) without the correctness actually _depending_ on it. Both orders may be equally correct :).
Apr 27 2007
prev sibling parent James Dennett <jdennett acm.org> writes:
Bruno Medeiros wrote:
 Frits van Bommel wrote:
 Bruno Medeiros wrote:
 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.
IIRC[1] the C++ standard includes "causes a compile error" as one of the possible consequences of undefined behavior. I'm not sure about C. [1] I've been staying away from C++ since I started using D, so this is by no means a given...
I haven't read about C++ in detail, only C. But in both cases (and sometimes here in the NG too) I often see the documents call "undefined behavior" to thing they should call errors. They refer to these concepts almost interchangeably, whereas they are not. They overlap a lot but they are not the same, there is a subtle difference.
The difference is huge, not subtle. Using undefined behavior (unless you're writing non-portable code and your implementation offers an extension that defines it) is *always* an error of a serious kind. Many errors require diagnostics from a C or C++ compiler; UB does not place *any* requirement on a compiler, which is allowed to fail to translate the code, to issue error messages, or to generate code that does *anything*.
 Dereferencing a trash pointer, for example, *is* an error. It *causes*
 undefined behavior, but it *is not* merely undefined behavior: it *can
 crash* your program.
Undefined behavior, formally, always has that potential. (In fact, it might be reasonable to say that the only ways to "crash" a C or C++ program are through the use of undefined behavior, and it is certainly correct to say that a crash is always a permitted consequence of using undefined behavior.)
 On the other hand if do 
   func(i++, i++);
 where func simply prints prints its arguments, I will have undefined
 program behavior, but no program error : that code *can not ever* crash
 the program. (altough it is still likely a *conceptual* error)
It can crash your program, or cause it to fail to compile. It's undefined behavior. Undefined behavior, unless specifically allowed by your implementation, means that all bets are off. Optimizers can assume that you won't violate the sequence point rules, and can do unbounded things with that information (for example).
 This is a minor nitpick, since in practice both should be equally
 avoided, but that subtle difference is still there.
Misunderstandings of what undefined behavior means are common, but I'm not sure that your message clarifies. (In C++ the order of evaluation is unspecified, not undefined; this can mean that some code fragments have UB because they violate rules on sequence points. This uses the terms as per the ISO C++ standard.) -- James
Apr 27 2007
prev sibling next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
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
Apr 26 2007
next sibling parent =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> writes:
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
Apr 26 2007
prev sibling parent =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> writes:
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
Apr 26 2007
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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.)
Apr 26 2007
next sibling parent reply Russell Lewis <webmaster villagersonline.com> writes:
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
Apr 26 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
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
Apr 26 2007
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Manfred Nowak wrote:
 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.
I don't understand what you're saying here; perhaps your definition was too indirect? What are you wanting to define orders for, and what not? Moreover, if it's not an issue, then why did Walter bring it up? Apparently it *is* an issue.
Apr 27 2007
next sibling parent reply Sean Kelly <sean f4.ca> writes:
Russell Lewis wrote:
 Manfred Nowak wrote:
 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.
I don't understand what you're saying here; perhaps your definition was too indirect? What are you wanting to define orders for, and what not? Moreover, if it's not an issue, then why did Walter bring it up? Apparently it *is* an issue.
It's an issue because it's confusing, as previous discussions can attest. I'm still not convinced that there is sufficient reason to define an evaluation order, since most other languages don't and it doesn't seem to be a problem, but I'll admit that it would make for less confusion. Sean
Apr 27 2007
next sibling parent Russell Lewis <webmaster villagersonline.com> writes:
Sean Kelly wrote:
 It's an issue because it's confusing, as previous discussions can 
 attest.  I'm still not convinced that there is sufficient reason to 
 define an evaluation order, since most other languages don't and it 
 doesn't seem to be a problem, but I'll admit that it would make for less 
 confusion.
Maybe a simpler solution (harder for Walter, probably, but simpler for everybody else) would be to have the compiler start issuing errors when these undefined syntaxes are used. :)
Apr 27 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Sean Kelly wrote:
 Russell Lewis wrote:
 Manfred Nowak wrote:
 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.
I don't understand what you're saying here; perhaps your definition was too indirect? What are you wanting to define orders for, and what not? Moreover, if it's not an issue, then why did Walter bring it up? Apparently it *is* an issue.
It's an issue because it's confusing, as previous discussions can attest. I'm still not convinced that there is sufficient reason to define an evaluation order, since most other languages don't and it doesn't seem to be a problem, but I'll admit that it would make for less confusion. Sean
What do you mean by "most other languages"? Have you seen my other post have well defined evaluation orders? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 27 2007
parent reply Sean Kelly <sean f4.ca> writes:
Bruno Medeiros wrote:
 Sean Kelly wrote:
 It's an issue because it's confusing, as previous discussions can 
 attest.  I'm still not convinced that there is sufficient reason to 
 define an evaluation order, since most other languages don't and it 
 doesn't seem to be a problem, but I'll admit that it would make for 
 less confusion.
What do you mean by "most other languages"? Have you seen my other post have well defined evaluation orders?
True. I suppose I should have said "most other languages I've used" :-p I'm wondering if it's fair to include languages that don't support operator overloading though, or multiple calling conventions. Can a strong parallel be drawn between D and any of the languages you mention, insofar as this issue is concerned? Sean
Apr 27 2007
next sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Sean Kelly wrote:
 Bruno Medeiros wrote:
 Sean Kelly wrote:
 It's an issue because it's confusing, as previous discussions can 
 attest.  I'm still not convinced that there is sufficient reason to 
 define an evaluation order, since most other languages don't and it 
 doesn't seem to be a problem, but I'll admit that it would make for 
 less confusion.
What do you mean by "most other languages"? Have you seen my other all have well defined evaluation orders?
True. I suppose I should have said "most other languages I've used" :-p I'm wondering if it's fair to include languages that don't support operator overloading though, or multiple calling conventions. Can a strong parallel be drawn between D and any of the languages you mention, insofar as this issue is concerned? Sean
But I don't see how operator overloading or calling conventions would have any effect on having a completely defined expression order of evaluation. Indeed, I don't think it makes any difference. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 29 2007
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Bruno Medeiros wrote:

 But I don't see how operator overloading or calling conventions would
 have any effect on having a completely defined expression order of
 evaluation. Indeed, I don't think it makes any difference.
Python:
 class FakeInt:
def __init__(self, v): self.v = v def __add__(self, rhs): return FakeInt(self.v+rhs.v) def __str__(self): return str(self.v)
 FakeInt(2) + FakeInt(3)
5 -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Apr 29 2007
prev sibling parent reply Jan Claeys <usenet janc.be> writes:
Op Fri, 27 Apr 2007 18:42:12 -0700
schreef Sean Kelly <sean f4.ca>:

 Bruno Medeiros wrote:
 Sean Kelly wrote:
 It's an issue because it's confusing, as previous discussions can 
 attest.  I'm still not convinced that there is sufficient reason
 to define an evaluation order, since most other languages don't
 and it doesn't seem to be a problem, but I'll admit that it would
 make for less confusion.
What do you mean by "most other languages"? Have you seen my other Ruby all have well defined evaluation orders?
True. I suppose I should have said "most other languages I've used" :-p I'm wondering if it's fair to include languages that don't support operator overloading though, or multiple calling conventions.
Python supports operator overloading and "multiple calling conventions"? ;-) -- JanC
Apr 29 2007
parent Sean Kelly <sean f4.ca> writes:
Jan Claeys wrote:
 Op Fri, 27 Apr 2007 18:42:12 -0700
 schreef Sean Kelly <sean f4.ca>:
 
 Bruno Medeiros wrote:
 Sean Kelly wrote:
 It's an issue because it's confusing, as previous discussions can 
 attest.  I'm still not convinced that there is sufficient reason
 to define an evaluation order, since most other languages don't
 and it doesn't seem to be a problem, but I'll admit that it would
 make for less confusion.
What do you mean by "most other languages"? Have you seen my other Ruby all have well defined evaluation orders?
True. I suppose I should have said "most other languages I've used" :-p I'm wondering if it's fair to include languages that don't support operator overloading though, or multiple calling conventions.
Python supports operator overloading and "multiple calling conventions"? ;-)
Ah well :-) I suppose I'm just worried we'd be trading away a potential for optimization for support of a coding strategy that no one should be using anyway. Sean
Apr 30 2007
prev sibling parent Manfred Nowak <svv1999 hotmail.com> writes:
Russell Lewis wrote

 Manfred Nowak wrote:
 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.
I don't understand what you're saying here; perhaps your definition was too indirect? What are you wanting to define orders for, and what not?
Have a look at one of Brunos examples: | c = a + (b = c); There seem to exist some cases where evaluation order matters. This is because the coder might have believed in evaluating this expression as the sequence: b = c; c = a + b; // c == a + c or as the sequence: c = a + b; b = c; // b == a + c which might be different, if one of the following conditions holds: a != 0 b != c If it can be deduced from the context, that none of this conditions holds, then there is no need to define an order and thus no need to "prevent optimizers from doing all that they can conceive of". OTOH if it can be deduced from the context, that at least one of this conditions might hold then Brunos requirement kicks in.
 Moreover, if it's not an issue, then why did Walter bring it up? 
 Apparently it *is* an issue.
I do not realize that Walter wants to extend Brunos requirement. -manfred
Apr 27 2007
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Walter Bright wrote

 it isn't easy to do
If it is not easy to define the order for the specs, then it will not be easy to learn, then near to nobody will know of or rely on the definition in the specs. Remember that even M$ recommends to fully parenthese expressions <because others might not know how to evaluate expressions without parentheses>. You once said, that you want to prohibit the upcoming of D-guru's. But if you yourself are not able to immediately sketch such order here, then you have the proof of upcoming gurus. If it is not easy to code then above arguments holds for compiler writers too. -manfred
Apr 26 2007
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 
 it isn't easy to do
If it is not easy to define the order for the specs,
It's easy to define the order. It is not so easy to implement it.
Apr 26 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Walter Bright wrote
 It's easy to define the order.
Then please do so right now. -manfred
Apr 26 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 It's easy to define the order.
Then please do so right now.
Then I'd have a pile of bug reports because it isn't so easy to implement.
Apr 26 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Walter Bright wrote

 Then I'd have a pile of bug reports because it isn't so easy to
 implement.
Why that, when it isn't in the specs, only in this forum, and declared as a draft definition? Please do not declare that the thinking capabilities of average D-users are that low. -manfred
Apr 26 2007
next sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 
 Then I'd have a pile of bug reports because it isn't so easy to
 implement.
Why that, when it isn't in the specs, only in this forum, and declared as a draft definition? Please do not declare that the thinking capabilities of average D-users are that low. -manfred
I don't think he means bugs in users' code (although there would probably be a handful of them, most likely quick-fixes though). I think he actually means bugs in the compiler, which are worth more time spent investigating implementation details to avoid. -- Chris Nicholson-Sauls
Apr 26 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 
 Then I'd have a pile of bug reports because it isn't so easy to
 implement.
Why that, when it isn't in the specs, only in this forum, and declared as a draft definition? Please do not declare that the thinking capabilities of average D-users are that low. -manfred
Someone with a non-low average thinking capability (*grin* :) ) would easily deduce that the evaluation order will be the same as any other have all the same evaluation order). The rule in a general sense is: Evaluate operands in the same order as the associativity rule of the operator. So stuff like this: c = a + (b = c); evaluates in this order: a c b (b = c) a + (b = c) c c = a + (b = c) A function call, since it is basicly an operator that takes a function value and arguments as operands, works in the same rule. So: func(++i, ++c); evaluates: func ++i ++c func(++i, ++c) I don't think there is any significant learning process involved here. If you know the associativity rules (which you should), then the evaluation order is simply what naturally follows from there. You don't have to memorize a whole different set of rules. In fact the assignments are basicly the only operators where the operands are evaluated right-to-left. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 27 2007
next sibling parent Russell Lewis <webmaster villagersonline.com> writes:
Bruno Medeiros wrote:
 Someone with a non-low average thinking capability (*grin* :) ) would 
 easily deduce that the evaluation order will be the same as any other 

 have all the same evaluation order). The rule in a general sense is:
Be careful when you imply "everybody who thinks differently than I is stupid." I can confidently state that I have non-low average thinking capability, and it is far from clear to me. I had to look pretty hard at your analysis below to make sure that I knew what seemed so "obvious" to you. My simple question is: why are we worrying about defining the behavior of code snippets which are bad coding style? There are clearer, more explicit ways to accomplish the same task, that do not require that we define the order of operations.
   Evaluate operands in the same order as the associativity rule of the 
 operator.
 
 So stuff like this:
   c = a + (b = c);
 evaluates in this order:
   a
   c
   b
   (b = c)
   a + (b = c)
   c
   c = a + (b = c)
 
 A function call, since it is basicly an operator that takes a function 
 value and arguments as operands, works in the same rule. So:
   func(++i, ++c);
 evaluates:
   func
   ++i
   ++c
   func(++i, ++c)
 
 I don't think there is any significant learning process involved here. 
 If you know the associativity rules (which you should), then the 
 evaluation order is simply what naturally follows from there. You don't 
 have to memorize a whole different set of rules. In fact the assignments 
 are basicly the only operators where the operands are evaluated 
 right-to-left.
If there is no significant learning process involved, then why did you need to state it here? Surely everybody knew the rules already. If not everybody knew the rules, there is a learning process involved...and apparently it's nontrivial, at least to some people.
Apr 27 2007
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Bruno Medeiros wrote

    Evaluate operands in the same order as the associativity rule
    of the 
    operator.
You require all operators to have an associativity? Then what is the associativity of the operators for comparison?
 So stuff like this:
    c = a + (b = c);
 evaluates in this order:
Seems arbitrary choosen to me.
 A function call, since it is basicly an operator that takes a
 function value and arguments as operands, works in the same rule.
I see now, that you want a defined order for all expressions. Then imagine an arbitrary sequence of assignments: are you able to identify the regions of that sequence that are in existence only because the coder wants to use an ordering other then the predefined? If you are able to do so and someone declares that he is not able to do so then how would you teach him that capability of yours? Please start immediately under the fiction, that I am not able to identify those regions. -manfred
Apr 27 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Manfred Nowak wrote:
 Bruno Medeiros wrote
 
    Evaluate operands in the same order as the associativity rule
    of the 
    operator.
You require all operators to have an associativity? Then what is the associativity of the operators for comparison?
Huh? "require all operators to have an associativity"?... Any C-based language has an associativity rule for all operators! Didn't you know that?? The associativity for comparison operators is listed here: http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B (it's the same in D) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 29 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Bruno Medeiros wrote

 (it's the same in D) 
| Comparison operators are no longer associative changelog for D 1.007 Sadly you seem unwilling to state your capabilities with respect to identifying assignment subsequences wich can be specifically attributed. -manfred
Apr 29 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Manfred Nowak wrote:
 Bruno Medeiros wrote
 
 (it's the same in D) 
| Comparison operators are no longer associative changelog for D 1.007
Hum, you're right, I forgot about that, sorry. So, going back to your original question: Manfred Nowak wrote:
 Bruno Medeiros wrote

    Evaluate operands in the same order as the associativity rule
    of the
    operator.
You require all operators to have an associativity? Then what is the associativity of the operators for comparison?
Ok, I understand the question. Very well, let's use a different learning rule: All operands are evaluated left to right, with the exception of the assignment operators which are evaluated right-to-left. I think it is even easier to learn than the previous one. Any problem with this one? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 01 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Bruno Medeiros wrote
 All operands are evaluated left to right, with the exception of
 the assignment operators which are evaluated right-to-left.
[...]
 Any problem with this one?
Don't you see a reason why Walter has tossed himself out of this thread? Given an expression `a op b' | The expression is rewritten as both: | a.opfunc(b) | b.opfunc_r(a) This is from the specs! Now what is the evaluation order of `a op b'? `a' then `b'? `b' then `a'? If there is a cloud some people only see the silver lining. -manfred
May 01 2007
next sibling parent Benji Smith <dlanguage benjismith.net> writes:
Manfred Nowak wrote:
 If there is a cloud some people only see the silver lining.
That's a great phrase! I'm stealing it for my own purposes :-) Thanks! --benji
May 01 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Manfred Nowak wrote:
 Bruno Medeiros wrote
 All operands are evaluated left to right, with the exception of
 the assignment operators which are evaluated right-to-left.
[...]
 Any problem with this one?
Don't you see a reason why Walter has tossed himself out of this thread? Given an expression `a op b' | The expression is rewritten as both: | a.opfunc(b) | b.opfunc_r(a) This is from the specs! Now what is the evaluation order of `a op b'? `a' then `b'? `b' then `a'? If there is a cloud some people only see the silver lining. -manfred
Hum, good point. This looks like an unprecedented case, I don't know if any other languages have reverse operator overloading like D. In any case a design decision would have to be made (thus creating a new evaluation rule). I would say that the order should be 'a' then 'b', because this way the programmer doesn't have to check which operator function is being invoked to know the evaluation order of such expression. This makes the code less dependent, which is particularly important since the underlying operator function could change in time, (from a non-reverse, to a reverse one, for example), and it would be best to maintain the original order semantics. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 06 2007
next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Bruno Medeiros wrote:
 Hum, good point. This looks like an unprecedented case, I don't know if
 any other languages have reverse operator overloading like D.
Rubbish. Python does as well, and for precisely the same reason I suspect D does: non-commutative operations, and working with existing, closed types. For instance, if you have a pre-existing, closed vector class, and you want to write a matrix class that works with it, you need to overload both opMul and opMul_r, or it won't work. I'd argue that any language that *doesn't* let you write the reverse operation is doing a pretty half-arsed job of operator overloading... Hell, I wrote vector and matrix structs from scratch, and I did it that way since having two templates depend on each other causes MORE than enough problems... I'm not entirely sure I fixed the data corruption issue it was causing, and I'd really rather not wrangle with that again. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 06 2007
prev sibling parent Manfred Nowak <svv1999 hotmail.com> writes:
Bruno Medeiros wrote

 In any case a design decision would have to be made
There is at least one more such decision to be made. But what are they worth when it is anticipated, that the hardware will be able to evaluate complex expressions if there are no evaluation orders to be followed. -manfred
May 07 2007
prev sibling parent janderson <askme me.com> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 
 it isn't easy to do
If it is not easy to define the order for the specs, then it will not be easy to learn, then near to nobody will know of or rely on the definition in the specs. Remember that even M$ recommends to fully parenthese expressions <because others might not know how to evaluate expressions without parentheses>. You once said, that you want to prohibit the upcoming of D-guru's. But if you yourself are not able to immediately sketch such order here, then you have the proof of upcoming gurus. If it is not easy to code then above arguments holds for compiler writers too. -manfred
I agree. Furthermore, I strongly think it should be left as is. Why, because when I comeup against weird code like that, I don't want to have to consult the spec. Its like implicit casting, if you don't know what is happening your going to have a terrible time figuring out what is happening. This is one area where I think D could do a lot more to help the programmer avoid mistakes. Furthermore if its difficult to implement, you've just made D harder for someone else to implement. Please reconsider putting this in. -Joel
Apr 26 2007
prev sibling parent Dan <murpsoft hotmail.com> writes:
I tend to think if it's ambiguous it shouldn't be allowed.  I most definitely
do not want to be consulting an operator precedence chart every time I try to
read other people's code.

I personally think that shit like:

for(i=0;i<x.length;){ if(i+=++i+3){ x[i][--i]; continue; } i++; }

is starting to get really really bad... I wouldn't want to ever see 2000 lines
of that shit.
Apr 28 2007