Order of Evaluation of Function Parameters

Order of evaluation in C++ function parameters

No, there's no such guarantee. It's unspecified according to the C++ standard.

Bjarne Stroustrup also says it explicitly in "The C++ Programming Language" 3rd edition section 6.2.2, with some reasoning:

Better code can be generated in the
absence of restrictions on expression
evaluation order

Although technically this refers to an earlier part of the same section which says that the order of evaluation of parts of an expression is also unspecified, i.e.

int x = f(2) + g(3);   // unspecified whether f() or g() is called first

function parameter evaluation order

C and C++ are two completely different languages; don't assume the same rules always apply to both. In the case of parameter evaluation order, however:

C99:

6.5.2.2 Function calls
...

10 The order of evaluation of the function designator, the actual arguments, and
subexpressions within the actual arguments is unspecified, but there is a sequence point
before the actual call.

[Edit]
C11 (draft):

6.5.2.2 Function calls
...

10 There is a sequence point after the evaluations of the function designator and the actual
arguments but before the actual call. Every evaluation in the calling function (including
other function calls) that is not otherwise specifically sequenced before or after the
execution of the body of the called function is indeterminately sequenced with respect to
the execution of the called function.94)
...

94) In other words, function executions do not ‘‘interleave’’ with each other.

C++:

5.2.2 Function call
...

8 The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect
before the function is entered. The order of evaluation of the postfix expression and the argument expression list is
unspecified.

Neither standard mandates the use of the hardware stack for passing function parameters; that's an implementation detail. The C++ standard uses the term "unwinding the stack" to describe calling destructors for automatically created objects on the path from a try block to a throw-expression, but that's it. Most popular architectures do pass parameters via a hardware stack, but it's not universal.

[Edit]

I am getting confusing information from the books.

This is not in the least surprising, since easily 90% of books written about C are simply crap.

While the language standard isn't a great resource for learning either C or C++, it's good to have handy for questions like this. The official™ standards documents cost real money, but there are drafts that are freely available online, and should be good enough for most purposes.

The latest C99 draft (with updates since original publication) is available here. The latest pre-publication C11 draft (which was officially ratified last year) is available here. And a publicly availble draft of the C++ language is available here, although it has an explicit disclaimer that some of the information is incomplete or incorrect.

Parameter evaluation order before a function calling in C

No, function parameters are not evaluated in a defined order in C.

See Martin York's answers to What are all the common undefined behaviour that c++ programmer should know about?.

What is the order of evaluation for function arguments in Javascript?

All the operators in JavaScript evaluate their operands left-to-right, including the function call operator. First the function to call is evaluated then the actual parameters in left-to-right order.

Section 11.2.3 is the relevant spec section.

11.2.3 Function Calls

...

2 Let func be GetValue(ref).

3 Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).

...

and you can see that the ArgumentList production is left-recursive

11.2.4 Argument lists

...

The production ArgumentList : ArgumentList , AssignmentExpression is evaluated as follows

and ArgumentList is evaluated before AssignmentExpression in the following verbiage..

Under EcmaScript 3 some of the comparison operators (<, <=, >, >=) evaluated right to left since a<=b was defined in terms of !(b<a), but that was widely recognized as a spec error, major interpreters did not implement it that way, and it was fixed in EcmaScript 5.

From the language spec:

11.8.5 The Abstract Relational Comparison Algorithm # Ⓣ

The comparison x < y, where x and y are values, produces true, false, or undefined (which indicates that at least one operand is NaN). In addition to x and y the algorithm takes a Boolean flag named LeftFirst as a parameter. The flag is used to control the order in which operations with potentially visible side-effects are performed upon x and y. It is necessary because ECMAScript specifies left to right evaluation of expressions. The default value of LeftFirst is true and indicates that the x parameter corresponds to an expression that occurs to the left of the y parameter’s corresponding expression. If LeftFirst is false, the reverse is the case and operations must be performed upon y before x. Such a comparison is performed as follows:

What is the evaluation order of function arguments?

The source of confusion and different output is the order of evaluation of the arguments.

Look at your example:

m("A", a, SetAI(&a))

This is a function call, the function value and arguments are evaluated in the usual order:

Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.
For example, in the (function-local) assignment

y[f()], ok = g(h(), i()+x[j()], <-c), k()

the function calls and communication happen in the order f(), h(), i(), j(), <-c, g(), and k(). However, the order of those events compared to the evaluation and indexing of x and the evaluation of y is not specified.

So basically the spec only guarantees that function calls and communication
ops happen from left-to-right.

Your call has arguments "A", a and SetAI(&a). There is no guarantee if the second argument a is evaluated before the &a param passed to SetAI(), and this very much matters because SetAI() modifies a. Since the order is not guaranteed, you can't rely on which will be evaluated first, both order is valid by the spec.

If you make the evaluation explicit by doing a copy of the struct before, you get the same result:

a := A{}
aCopy := a
m("A", aCopy, SetAI(&a))
b := B{}
bCopy := b
m("B", bCopy, SetBI(&b))

This will output (try it on the Go Playground):

A: {0 } {10 }
B: {0} {10}

Or if you want the function call to be evaluated first:

a := A{}
ap := SetAI(&a)
m("A", a, ap)
b := B{}
bp := SetBI(&b)
m("B", b, bp)

This will output 10 for each cases (try this one on the Go Playground):

A: {10 } {10 }
B: {10} {10}

What is the order of evaluation of function arguments java

The evaluation of arguments is described by JLS 15.12.4.2.

An excerpt:

The argument expressions, if any, are evaluated in order, from left to
right. If the evaluation of any argument expression completes
abruptly, then no part of any argument expression to its right appears
to have been evaluated, and the method invocation completes abruptly
for the same reason. The result of evaluating the j'th argument
expression is the j'th argument value, for 1 ≤ j ≤ n.

Applying this to your case the evaluation order is:

ExampleFunction(new ExampleObject("Test", new ExampleObject("Test2")));
- new ExampleObject("Test", new ExampleObject("Test2"))
- - "Test"
- - new ExampleObject("Test2")
- - - "Test2"

This is the order in which the arguments are called for evaluation. This means in turn that to evaluate new ExampleObject("Test", new ExampleObject("Test2")) first new ExampleObject("Test2") will be evaluated.

Is Python's order of evaluation of function arguments and operands deterministic (+ where is it documented)?

Yes, left to right evaluation order is guaranteed, with the exception of assignments. That's documented here (py2, py3):

Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.

In the following lines, expressions will be evaluated in the arithmetic order of their suffixes:

expr1, expr2, expr3, expr4
(expr1, expr2, expr3, expr4)
{expr1: expr2, expr3: expr4}
expr1 + expr2 * (expr3 - expr4)
expr1(expr2, expr3, *expr4, **expr5)
expr3, expr4 = expr1, expr2

If the language were not making some choice about this, the evaluation of one argument could mutate another argument and result in unspecified behaviour, so all implementations of Python must follow this spec.

Order of evaluation of function arguments in PHP

Usually, yes. As the manual states:

[Function] arguments are evaluated from left to right.

But there are two edge cases where arguments are not evaluated at all:

Undefined functions

$calls = 0;
register_shutdown_function(function () use (&$calls) {
echo $calls;
});
func_does_not_exist($calls++);

This outputs 0 on all versions of PHP.

Missing constructor, a special case of an undefined function

class Foo {}

$bar = 0;
$foo = new Foo($bar++);
echo $bar;

This outputs 0 on PHP < 7.1, and 1 on PHP >= 7.1. It's been called the "Rasmus optimization", and it occurs only in the case of constructing classes without formal constructors. See also #67829, #54162 and #54170.


In summary, the manual is correct. For defined functions, arguments are evaluated left-to-right then passed into the function. Undefined functions, for which a non-existent constructor is a special case, do not qualify as functions and so the evaluation before calling is itself undefined.

Problem with order of evaluation in parameter pack expansion

For example, we can use an intermediate std::tuple to force the order of evaluation:

template<typename TR, typename ... TArgs>
TR Bar(std::istream &s, TR f(TArgs...) )
{
std::tuple<TArgs...> args{Parse<TArgs>(s)...};
return std::apply(f, std::move(args));
}

In contrast to function arguments, the order of evaluation of arguments in a braced list is fixed by their order in that list, [dcl.init.list/4]:

Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions, are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. ]

Why doesn't c++ have a specified order for evaluating function arguements?

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.



Related Topics



Leave a reply



Submit