4 ms·
Different architectures have their own function passing convention. It’s convenient to evaluate left-to-right, pushing as you go, if that matches the arch. And
by blake1 5y ago
Different architectures have their own function passing convention. It’s convenient to evaluate left-to-right, pushing as you go, if that matches the arch. And vice versa.
- tsimionescu 5y agoThat would explain why you want it implementation-defined, but leaving it indeterminate means that the same piece of code is allowed to have different evaluation orders each time it is encountered. This is much stranger, and very specific to C and C++, I don't think there is any other language that doesn't specify the order of execution.
- mannerheim 5y agoHaskell? Expressions have to be evaluated in order to evaluate expressions that depend on them, but otherwise the compiler is free to decide the order of evaluation. > In this case, it's pretty easy to see that 3 will have to be printed after both 1 and 2, but it's unclear whether 1 or 2 will be printed first. The reason for this is evaluation order: in order to evaluate one + two, we'll need to evaluate both one and two. But there is nothing telling GHC which of those thunks should be evaluated first, and therefore GHC is at full liberty to choose whichever thunk to evaluate first. https://wiki.haskell.org/Evaluation_order_and_state_tokens https://wiki.haskell.org/Evaluation_order_and_state_tokens
- tsimionescu 5y agoWell, Haskell's lazy execution model and implicit purity makes this far different from C++. The examples there all rely on the guarantee-breaking unsafePerformIO, while in C++ you can break your program with perfectly safe,c normal C++ code, such as creating a shared pointer and throwing an exception. Note that in Haskell evaluation order is not guaranteed anywhere, even between separate statements, whereas in C++ it is basically guaranteed everywhere except function calls.
- mannerheim 5y agounsafePerformIO was there to make the indeterminate evaluation order visible, but isn't what causes that indeterminate evaluation order. You are right, though, that for 'safe' Haskell code the evaluation order shouldn't matter, although it is sort of a matter of convention; 'head' is unsafe, but is presumably now permanently stuck in the language, while on the other hand perhaps one could write C++ without exceptions, but that wouldn't be 'normal' C++ code.
- tsimionescu 5y agoSure, my point was that, as far as I understand, even Haskell code that performed IO would have a well-determined order, if it was doing normal IO; whereas C++ code that does something as simple and safe looking as foo(i++, i) may produce different results in different runs (it was even UB before C++17, and still us in C; and even other common idioms, such as function chaining, had undefined execution order).
- mannerheim 5y agoYes and no. The order IO is performed is well-defined (that's the purpose of the IO monad), but the evaluation order is not (apart from ordering arising from data dependency), and this is the case with or without unsafePerformIO. You just won't get any different behaviour with safe Haskell code, and Haskell is very much on the safe side of things, so even though the order of evaluation may be indeterminate, you would never notice it (maybe a timing attack is possible?). But this is admittedly hair-splitting.
- vnorilo 5y agoIf you think about how it interacts with inlining, it's easy to see how optimizers like this freedom. Suppose there's just one call that may throw and the others are pure functions. The compiler could bunch the pure ones together to optimize register and stack allocation.
- atq2119 5y agoThis is the correct answer, plus add loop unrolling etc. It is simply not possible to write an optimizing compiler in which the evaluation order is truly indeterminate yet always the same.
- tsimionescu 5y agoI was claiming it could be left implementation defined instead of unspecified. That way, code for particular platforms could be evaluated in different order, but it would always be deterministic for a particular compiler.
- vnorilo 5y agoThe optimized evaluation order would depend on the situation near at the call site, not the architecture or platform.
- tsimionescu 5y agoThe GP that my post was replying to was claiming it was arch dependent, and I was pointing out that, if it had been, they would have likely not left it unspecified. So, I think you and I are in agreement.
- tsimionescu 5y agoI would be truly shocked if this optimization ever mattered in practice. It would mean that rewriting code from { auto& a = <expression> auto& b = <expression> foo(a, b); } To foo(<expression>, <expression>); Could be an optimization. Edit: modified the code a bit to make the two samples more similar.