call chaining clarified
kris
foo at bar.com
Fri Mar 30 00:26:00 PDT 2007
Walter Bright wrote:
> 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.
Thank you for putting that to rest. Actually, thank you very much.
>>> 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.
No problemo
>>> 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.
Again, thanks for this clarification. Minor suggestion: perhaps some of
this might wind up in the docs? For instance, maybe a brief section on
call-chaining could act as a useful vehicle to clarify these aspects?
~ Kris
More information about the Digitalmars-d
mailing list