Order of evalution in method chaining

This post is related to my earlier one. Expanding on the subject of the order of evalutions, let’s start with an example:


class A
{
public :
    A() : _myValue(0) {};

    A& IncrVarTen()
    {
        _myValue += 10;
        cout << "value is:" << _myValue << endl;
        return *this;
    }

    A& IncrVarTwenty()
    {
        _myValue += 20;
        cout << "value is:" << _myValue << endl;
        return *this;
    }

    int _myValue;
};


int main()
{
    A a;
    a.IncrVarTen().IncrVarTwenty();
    cout << "Final value is:" << a._myValue << endl; 
    return 0;
}


What we see as the output is exactly as we would expect:

value is:10
value is:30
Final value is:30

From the standard in [expr.post / 5.2] paragram 1: “Postfix expressions group left-to-right.”

Let’s now introduce some arguments to the methods and pass by reference and value.

class A
{
public :
    A& PassByRef(int& i)
    {
        i += 10;
        cout << "PassByRef value of i=" << i << endl;
        return *this;
    }

    A& PassByValue(int i)
    {
        cout << "PassByValue value of i=" << i << endl;
        return *this;
    }
};


int main()
{
    A a;
    int i(0);
    a.PassByRef(i).PassByValue(i);

    cout << "Final value of i:" << i << endl; cin >> i;
    return 0;
}

Depending on your compiler, you may see as expected the value of 10 for all outputs, or the following:

PassByRef value of i=10
PassByValue value of i=0
Final value of i:10

What is happening here? How can PassByValue display 0? Let’s have a look at section [expr.call / 5.2.2] note 8, which states: “The evaluations of the postfix expression and of the arguments are all unsequenced relative to one another. All side effects of argument evaluations are sequenced before the function is entered”. What this means is the argument being passed by value can be loaded on a register ahead of the value being incremented in method PassByRef. This means we get the original value, and not the incremented value in PassByValue.

Final thoughts:
Chaining can be quite useful when it comes to expressing in a single line what would otherwise be multiples lines. It can make it easier on the eyes to quickly understand what the code does. Personally I do try to chain when there is a benefit. However as we just saw, it’s important to keep in mind there may be some consequences when using arguments with side effects.

Leave a Reply

Your email address will not be published. Required fields are marked *