On Monday, 25 May 2015 at 12:38:29 UTC, kinke wrote:
On Monday, 25 May 2015 at 08:00:15 UTC, Jonathan M Davis wrote:
It might be completely well-defined and consistent, but it may not be what you expect, and even if it is, a slight change to the code could change the order.

If the behavior isn't what I expect (and I don't think that's often case for left-to-right order), then the language should force me to express the intention differently. If it's not well-defined, I may not be aware of such issues until I use a different compiler.

It seems like you still don't understand. Yes, defining the order of evaluation within an expression as being left-to-right makes it easier to deal with what is directly inside the expression, and the compiler could be make to do that (and from the sounds of it likely will). It could also be made to not be fixed about the order of evaluation but give an error when it detects that the order of evaluation matters, so that expressions like

foo(++i, ++i);

give an error. But even so, the compiler _cannot_ be made to catch all such problems for you, because all it takes is starting to bury the problem within other function calls within the expression, and while the order of evaluation in such cases may very well be defined, whether it's going to do what you expect is a completely different matter. For instance, what if you had

int bar()
{
    return ++i;
}

foo(bar(), bar());

Now, because ++i is inside a call to another function, the compiler can no longer see that the arguments that you're using depend on one another. The results _are_ well-defined, but whether it's what you expect is another matter. With one extra layer like this, you'll probably see it, and it'll be doing what you want, but what if you have an expression like

auto f = foo(bar() + baz(bop(), beep() + boop()));

and 4 levels down into the call stack bar() and beep() both mutate a static or global variable - or some other shared resource. Then the result of this expression ends up depending on an order of evaluation issue that you can't see without really digging into the code, and the compiler sure isn't going to see for you. You might see that swapping the arguments around in the expression results in a different result when you think that it shouldn't, but just as likely, you wouldn't catch that, and a small change to the code later could change the results unexpectedly, which you might or might not notice.

Now, that sort of thing is all the more reason to avoid using static or global variables, and it's the sort of thing that I would hope good code would avoid. But defining the order of evaluation as left-to-right, doesn't make those problems go away. At best, it makes them consistent, and that may be worth it, but it's not a silver bullet. And it takes optimization opportunities away from the compiler, since in many cases, it can reorder how the expression is evaluated to make better use of the registers and whatnot. So, forcing the order of evaluation is not without its cons, even if it did solve all order of evaluation issues, and it really doesn't - especially when that often depends on what you expect.

Ketmar had a screwy example with arrays a while back that he was complaining bitterly about not working due to order of evaluation issues, but IIRC he had recursive function calls which affected each other and was having all kinds of problems just because he insisted on doing multiple things in an expression rather than splitting them out. And the results he was getting were completely consistent; they just weren't what he wanted. The order of evaluation mattered too much in the expressions that he was writing.

Ultimately, if you want to reduce the risk of bugs, you really should be writing expressions where the order of evaluation doesn't matter, or where it only matters based on operator precedence directly within the expression so that it really doesn't matter what other code is doing. And forcing left-to-right evaluation doesn't change that. All it really does is make what what's happening consistent. It doesn't mean that relying on it is a good idea or that it's going to fix anything but the some of the most basic order of evaluation issues.

Personally, I don't think that it's worth the cost in lost optimizations, but even if it is, my point here is really that at best it only fixes part of the problem.

- Jonathan M Davis

Reply via email to