another round of call-chaining mystery?

James Dennett jdennett at acm.org
Fri Mar 30 08:33:33 PDT 2007


kris wrote:
> James Dennett wrote:
>> kris wrote:
>>
>>> James Dennett wrote:
>>>
>>>> kris wrote:
>>>>
>>>>
>>>>> James Dennett wrote:
>>>>>
>>>>>
>>>>>> kris wrote:
>>>>>
>>>>> [snip]
>>>>>
>>>>>
>>>>>>> There never was any argument of which you claim. I simply noted that
>>>>>>> eval-order had been clarified before, using your usage of
>>>>>>> "eval-order"
>>>>>>> from within the same post. If you revisit, you'll see that was
>>>>>>> actually
>>>>>>> referring to call-chaining instead, so there's perhaps a misuse of
>>>>>>> terms:
>>>>>>>
>>>>>>> Cout.opCall("Hello, ").opCall(Cin.get);
>>>>>>>
>>>>>>> As you can see, there is only one parameter passed to each call, and
>>>>>>> therefore the order of /parameter/ eval is "not at stake here" (as I
>>>>>>> noted to Frits). 
>>>>>>
>>>>>>
>>>>>> There are two arguments to the second opCall.  One is
>>>>>> the result of Cout.opCall("Hello, ") and the other is
>>>>>> the result of Cin.get, and they can be evaluated in
>>>>>> either order unless some rule prohibits it.
>>>>>
>>>>> I think you'll find that call-chaining does not operate in that
>>>>> manner,
>>>>> James? If you look a bit closer, you'll see that the lhs has to be
>>>>> evaluated first, simply to get something to deref the rhs. Further,
>>>>> there is only one argument permitted to the opCall() itself
>>>>>
>>>>> For a fuller description, I suggest you bring it up with Walter
>>>>> instead?
>>>>
>>>>
>>>> Walter's post in this thread (<eui80b$19hl$1 at digitalmars.com>)
>>>> seems to confirm my viewpoint as quoted above.  If you still
>>>> don't think so after reading his message, I'd be interested
>>>> if you can explain where Walter's explanation differs from
>>>> mine.
>>>>
>>>> Regards,
>>>>
>>>> James.
>>>
>>> Simply because that's what Walter led us to believe a long time ago,
>>> James, and it is how the compiler is implemented. Don't know what else
>>> to tell you.
>>
>>
>> I doubt that Walter lead you to believe that the order of
>> evaluation was defined for the particular example code
>> under discussion here.  ("Call chaining" is not the issue
>> at hand; order of evaluation of function arguments is the
>> relevant issue.)
>>
> 
> *sigh*
> 
> let's tease a couple of things apart, James?

Yes, that's what I was trying to do.

> First, there is the
> question of call chaining operating in an ordered fashion.

If you mean the same thing that I do by "call chaining",
I've not had any doubt about it; simple logic forces it.

> Second,
> there's the question of whether the miserable example is "correct" or
> not. Would you agree?

There are multiple questions about the correctness of the
example.  One of them relates to whether Cin.get can be
called before output is written; others may be affected
by buffering.

>> Did you read the message of Walter's to which I referred?
> 
> Naturally

Good; I thought I'd check.

>> Walter wrote, today:
>>
>>
>>> 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.).
>>
>>
>> This is very concrete and very specific, and supports what
>> I wrote above.  Are you suggesting that you disagree with
>> this?  (If so, with what do you disagree: that Walter wrote
>> this, that it supports my viewpoint, or something else?)
> 
> You're tying two concerns together. Walter notes that the nested opCall
> is always called before the outer. This is consistent with the
> requirements for call-chaining (they should be called left to right).

The point I quoted for was the "otherwise the order is
undefined", which doesn't apply to only the opCall calls.

> The only question remaining is that of what happens with three chained
> calls.

No, it is not.  The issue you've not addressed is that
the right-hand argument to the second opCall might be
evaluated before its left-hand argument.  That's not
about "call chaining" according to any definition that
I have seen.  It's about function argument evaluation
order.  Would you please be able to address this point?
It's the crucial one, and (to my mind) the only one
where there appears to be substantive disagreement.

> I'm awaiting the answer from Walter, but I would certainly hope
> that call-chaining invocation order is maintained.
> 
> As for that sordid little example, it has generated way to much concern
> for something that should be merely of passing interest. It just happens
> to work because of output buffering, and no other reason.

I've not seen a coherent explanation of why it cannot
break if evaluation order is changed, except...

> In tango, the console is buffered and, in general, one has to flush the
> output before it will be emitted (just like a file). Console output has
> historically had a few 'shortcuts' added such as a newline adding a
> hidden .flush for interactive console usage. There is no newline in this
> daft example, and the only .flush present is on the first line. Thus,
> the example is relying on cleanup-code to flush the output buffers on
> its behalf. As I've noted before, this hardly exhibits good coding
> practice.

This covers it, thank you.  The output function may or
may not be called before Cin.get, but it doesn't matter
as the actual output will be buffered in this case,
given the small amount of it.

> To make it perfectly clear, there was *never* any claim or belief that
> the Cin.get is or was evaluated before the Cout("hello "). We all
> intuitively *know* that the "hello " should be emitted before the
> Cin.get, but it isn't in that example. Again, it is because of buffering
> and the complete lack of an intervening flush on the console output.
> 
> There's a good reason why "mystery" is in the topic line ;)

What is that?  (Seriously.)

> I do hope that helps?

It does, thank you.  We have just the one issue now, and
it's not interesting in the case of the little example
program.

-- James



More information about the Digitalmars-d mailing list