April 27, 2007
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 :).
April 27, 2007
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
April 27, 2007
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 modern programming language (not just Java, but C#, Python, even Ruby, 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.
April 27, 2007
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.
April 27, 2007
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
April 27, 2007
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. :)
April 27, 2007
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
April 27, 2007
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
April 28, 2007
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 which mentions that not only Java, but C#, Python, and even Ruby all have well defined evaluation orders?


-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
April 28, 2007
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 which mentions that not only Java, but C#, Python, and even 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.  Can a strong parallel be drawn between D and any of the languages you mention, insofar as this issue is concerned?


Sean