call chaining clarified
Walter Bright
newshound1 at digitalmars.com
Fri Mar 30 00:08:02 PDT 2007
kris wrote:
> Walter Bright wrote:
>> kris wrote:
>>
>>> Cout.opCall("Hello, ").opCall(Cin.get);
>>
>>
>> Given:
>> a.f(b,c);
>> can be equivalently written as:
>> f(a,b,c);
>>
>> we can transform:
>> Cout.opCall("Hello, ").opCall(Cin.get);
>> into:
>> opCall(opCall(Cout,"Hello, "), Cin.get);
>>
>> And it is transformed that way, because the optimizer/back end knows
>> nothing about member functions. They're just more function calls.
>>
>> The nested opCall will get called before the outer opCall, but
>> otherwise the order is undefined (and will change depending on the
>> function calling convention, whether it is a virtual call or not, etc.).
>
> Thank you for that clarification, Walter.
>
> You note that the inner opCall will be evaluated before the outer one;
> how is x.one(a).two(b).three(c) tranformed?
three(two(one(x,a),b),c)
The order of evaluation of x, a, b, and c is undefined, even though one
is always called before two, and two is always called before three.
>> I suggest that at a minimum, if you wish to retain the current design,
>> build a test into the test suite that verifies the required order of
>> evaluation.
>>
>> It's possible that in the future, to ensure source code portability of
>> D, that the order of evaluation will become fixed. Such a change is a
>> fair amount of work to accomplish, and will incur a runtime penalty
>> (the implementation defined order allows the compiler to rearrange
>> things to minimize register pressure). Even if the order was fixed, it
>> still might not be in the right order for call chaining to work as
>> your design needs it to.
>
> Do you mean in terms of generic call-chaining, or that example
> specifically? For example, will the code x.one().two().three() always
> execute one() before two() ?
Yes, that is equivalent to: three(two(one(x))). The problem comes when
there is more than one argument.
>> I also suggest that, with the maturing of the variadic template
>> capability of D, using it will side step the order of evaluation
>> problem completely. It'll still be an aesthetically pleasing design to
>> the user.
>
> That's certainly a possibility, Walter, but call-chaining is surely
> expected to operate in an orderly fashion regardless of whether it is
> used as an IO interface or not? For example, what happens if two() were
> to return a different object for three() to be applied against? It would
> surely be incorrect to generate code whereby three() were called against
> x instead? In other words, for call chaining to operate correctly the
> following pseudocode should likely hold true:
>
> # auto result = x.one().two().three();
>
> auto tmp1 = x.one();
> auto tmp2 = tmp1.two();
> auto result = tmp2.three();
>
> Is that incorrect?
Yes. The problem is when there are more than one arguments involved.
More information about the Digitalmars-d
mailing list