6

It seems to me that it's a very basic and necessary feature of any functional programming language to know the order in which the arguments of a function call will be evaluated. Am I wrong in this? Why doesn't C++ define this? Is it being discussed for any future version of C++?

Toby Speight
  • 23,550
  • 47
  • 57
  • 84
jDogg
  • 109
  • 6
  • 3
    The order the programmer writes the parameters may not be the optimal way to evaluate them. Leaving this unspecified, lets compilers optimize parameter evaluation. – StoryTeller - Unslander Monica Aug 04 '16 at 10:28
  • It was originally to allow better (micro-)optimisation. – Jarod42 Aug 04 '16 at 10:28
  • 1
    No you're not wrong. C legacy. Yes. C++17: http://stackoverflow.com/questions/38501587/what-are-the-evaluation-order-guarantees-introduced-by-c17 see also http://stackoverflow.com/questions/26911377/parameter-order-evaluation – doctorlove Aug 04 '16 at 10:28
  • 4
    If anything, the order of evaluation should *not* matter in a functional programming language. But C++ ain't one of those. – juanchopanza Aug 04 '16 at 10:43

3 Answers3

13

Why doesn't C++ do it this way?

For starters, C++ isn't a functional programming language.

And the fastest way to evaluate the arguments depends on the implementation and architecture, so the compiler gets to choose. We don't pay for what we don't use, in C++, so if you need to specify an evaluation order yourself then you can do so explicitly with named variables.

Although, continuing the theme of newer standards leaving behind sacred C++ paradigms, C++17 will sadly add some evaluation order guarantees, ruining all of that.

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
  • 2
    Sadly? Some of them where cases that permit certain idioms (already in use) to not be undefined. Are you against all of the added evaluation order guarantees, or some in particular? – Yakk - Adam Nevraumont Aug 04 '16 at 16:20
  • 6
    @Yakk: Nah I'm just racist against evaluation order guarantees :) – Lightness Races in Orbit Aug 04 '16 at 16:28
  • 3
    Why just against I evaluation'm guarantees Naor hder? – Yakk - Adam Nevraumont Aug 04 '16 at 20:24
  • @Yakk While amusing, an entirely irrelevant example. Atomicity and ordering are different things. Ordering is unspecified but the evaluations are still sequenced with respect to each other. Besides, my comment is a single argument, tyvm :) – Lightness Races in Orbit Aug 04 '16 at 23:46
  • In C++14, argument evaluations where not atomic with respect to each other (function calls are, but not argument evaluations). One of the things fixed in C++17! And I figured you where using operator whitespace ;) – Yakk - Adam Nevraumont Aug 05 '16 at 00:07
  • I have to agree that adding such guarantees is a bad idea. Before we have the rule - "there are no guarantees - so don't use function calls with side effects as function arguments". The compiler would be allowed to schedule them on different threads. Now we have, "You may presume that function arguments are evaluated one at a time from left to right? (or is it right to left?, or?). So it's a more complex rule to remember and I can't see how the compiler could optimism this. – Robert Ramey Aug 06 '16 at 17:12
  • @Robert no, multiple threads is not allowed. You aren't allowed to interleave the parts of one function call with another function call: you could just (pre C++17) interleave the parameter evaluation etc. And similar. Naturally this only holds up to "as-if". – Yakk - Adam Nevraumont Aug 06 '16 at 19:59
  • Thanks for the details about C++17. I think this supports my point though. Now we can't expect that with f(a(d), b(c)) a and b might be evaluated in parallel if convenient whereas before we could. Code which depends upon the order of execution of a(d) and b(c) in this example is dependent on behavior which is implicit and not obvious from reading the code itself. I think this often leads to errors and surprising behavior. I think this is a net loss – Robert Ramey Aug 07 '16 at 17:56
  • @RobertRamey: Given a programmer who doesn't understand the basics of the language in which they're writing, yes I'd agree it's a net loss. – Lightness Races in Orbit Aug 07 '16 at 18:50
  • @robert No, a and b could never be evaluated in parallel; implicitly interleving function calls (other than as if we did not) has never been allowed in C++. Prior to 17, they could evaluate d, then c, then b(c) then a(d). After, they must evaluate a(d) or b(c) first, then the other. Which of a(d) or b(c) is first remains unspecified. The order guarantees are like f(a,b,c) evaluating f first, or m.foo(a,b,c) evaluating m first. – Yakk - Adam Nevraumont Apr 11 '21 at 21:11
  • "a and b could never be evaluated in parallel". Hmmmm - where does it say that? – Robert Ramey Apr 12 '21 at 22:30
10

As of C++17 it guarantees arguments will be evaluated linearly and will not interleave but not in any specific order - https://channel9.msdn.com/Shows/C9-GoingNative/GoingNative-52-ISO-C-Oulu-Debriefing

The reason it didn't before was to allow compiler implementers the scope to optimise the order of evaluation, it turned out not to be used or to be used poorly to the extent that logical order can and will be enforced with negligible impact.

EDIT: correction, thanks @Oktalist

I actually think this is an odd decision, it seems obvious to me that interleaving is an easier optimisation than argument evaluation reordering and I don't think we're going to treat argument evaluation with any more trust than we did before.

1stCLord
  • 854
  • 5
  • 14
  • 6
    Given `o.f(a, b)` C++17 says that `o` is evaluated before `f`, which is evaluated before `a` and `b`, and subexpressions of `a` and `b` will not be interleaved, but still does not specify the order in which `a` and `b` will be evaluated. – Oktalist Aug 10 '16 at 16:38
  • "Every value computation and side effect associated with the initialization of a parameter, and the initialization itself, is sequenced before every value computation and side effect associated with the initialization of any subsequent parameter." quoted from - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf – 1stCLord Aug 10 '16 at 16:44
  • See section 8 of that paper; it is the alternate version that was [voted](https://twitter.com/chandlerc1024/status/746328383345172480) into the standard at Oulu in June. – Oktalist Aug 10 '16 at 16:55
  • [N4604](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4604.pdf) is the new draft standard. – Oktalist Aug 10 '16 at 17:11
  • @Oktalist I rewatched the video and read the relevant section and you're right, sorry, i'll correct my answer. – 1stCLord Aug 10 '16 at 17:50
  • 2
    Re your edit, I don't think the intention was for us to have any more trust in evaluation order than we had before, but to standardize the things that everyone (including the experts) had already been mistakenly trusting. Correctness before optimization. – Oktalist Aug 10 '16 at 19:23
5

C++ is not a functional programming language. In fact in such a language (with no side effects), order of evaluation would not matter.

C++ leaves as much as practical up to the implementation of the compiler, especially where optimization opportunities might occur. Before fixing something like this, existing compiler writers are consulted to see if there is a cost.

Some order of evaluation guarantees surrounding overloaded operators and complete-argument rules were added in C++17. But it remains that which argument goes first is left unspecified. In C++17, it is now specified that the expression giving what to call (the code on the left of the ( of the function call) goes before the arguments, and whichever argument is evaluated first is evaluated fully before the next one is started, and in the case of an object method the value of the object is evaluated before the arguments to the method are. (There may be some minor errors in this description: ask a narrow question about it for a more vetted answer).

These were vetted and determined to not cause significant problems for existing compilers. Reordering of arguments was considered, and discarded, presumably for good reasons. Or even poor reasons, like existing compilers have a default order and it could break (possibly non-compliant) code on that compiler to force them all to do it in one global order.

In short, C++ leaves lots of freedom to compiler writers. This has let compiler writers find optimization opportunities in strange crannies. The kind of optimizations available today are way beyond what the original writers of C, let alone C++, may have suspected were practical or be considered reasonable.

Yakk - Adam Nevraumont
  • 235,777
  • 25
  • 285
  • 465