March 30, 2007
Derek Parnell wrote:
> On Thu, 29 Mar 2007 23:14:09 -0700, kris wrote:
> 
> 
> 
>>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?
> 
> 
> I'm guessing ...
> 
>    three( two( one(x, a), b), c);
> 
> thus either 'x' or 'a' is done first, then the other
>  then either 'one' or 'b', then the other
>  then either 'two' or 'c', then the other
>  and finally 'three'

That's fine. One is invoked before two, before three. No other expectations are in place

>    
> 
>>>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() ?
> 
> 
> I think it would. But in the case of  "x.one(a).two(b)" then you can't be
> sure if 'one' or 'b' will be evaluated first.

That's cool, Derek. The only expectation is that one is called before two

> 
> 
>>>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?
> 
> 
> I think Walter is saying that a test similar to ...
> 
>   auto tmpA = x.one(a).two(b).three(c);
>   auto tmp1 = x.one(a);
>   auto tmp2 = tmp1.two(b);
>   auto tmp3 = tmp2.three(c);
>   assert( tmpA is tmp3);
> 

I would hope that would always pass, since without it, plain old call-chaining would not function dependably (ingoring all the a, b, and c's)

Thanks for fleshing this out like you have
March 30, 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.
March 30, 2007
Derek Parnell wrote:
> On Thu, 29 Mar 2007 22:40:34 -0700, 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.). 
> 
> 
> Now that makes sense. I can see now why the W&A show is concerned. In fact,
> the call-chaining example seems to flesh out to ...
> 
>    opCall(opCall(Cout,"Hello, "), get(Cin));
> 
> which means that either the 'get' could be called first or the inner
> 'opCall' could be called first. One can never be sure.

No problemo


> This would mean that the sequence example given by Kris ...
> 
>     Cout ("Please enter your name: ").flush;
>     Cout ("Hello, ") (Cin.get);
> 
> gets transformed in to 
> 
>     flush( opCall( Cout, "Please enter your name: "));
>     opCall( opCall( Cout, "Hello, "), get(Cin));
> 
> The first statement will end up displaying the text on the console, leaving
> the cursor to the right of the ':' character. Now if the 'get' is called
> next, the user types in her name, say "mavis" and the screen will show ...
> 
>   Please enter your name: mavis
>   _
> 
> and then the inner 'opCall' is run which will show (assuming a flush) ...
> 
>   Please enter your name: mavis
>   Hello, mavis
>   _

Yes, although the second newline does not exist


> However, if the inner 'opCall' is called first the screen will show ...
> 
>   Please enter your name: Hello, _

That's where the tricky example is fooling everyone. In short, the example operates "correctly" (at least, on Win32) regardless of which way the execution occurs. In other words, it is not dependent upon execution order. It makes no assumptions there whatsoever ;)


> 
> and the user types in her name and we get ...
> 
>   Please enter your name: Hello, mavis
>   mavis
>   _
> 
> 
> So the order is reasonable important to sort out.

That may be so, but as long as call-chaining operates in a left to right order, Tango doesn't care about which order parameters are evaluated. Again, the example is leading everyone on a wild goose chase. If there's one thing I'll regret from this NG, it will be posting that trivial bit of mind-bending

> 
> Being the conservative procedural type of coder, I would have probably have
> coded ...
> 
>     char[] userName;
>     Cout ("Please enter your name: ").flush;
>     userName = Cin.get();
>     Cout ("Hello, ");
>     Cout (userName);
>     Cout.flush;
> 
> Actually, now that I think about it, I'd really do ...
> 
>     char[] userName;
>     char[] myResponse;
> 
>     Cout ("Please enter your name: ");
>     Cout.flush;
>     userName = Cin.get();
>     myResponse = std.string.format("Hello, %s\n", userName);
>     Cout.( myResponse );
>     Cout.flush;

And I would generally do

    Cout ("Please enter your name: ") ();
    auto name = Cin.get;
    Cout ("Hello, ")(name) ();

Which amounts to the same thing, I expect?


> That is of course, if I'd really used stdin/stdout in that manner at all
> <G>

Bingo! It blows me away just how much attention the lowly console is recieving :)
March 30, 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
March 30, 2007
James Dennett wrote:
[...]
> Now, please just accept that I consider such attacks on
> a person to be inappropriate, that they meet definitions
> of "flaming" that are in common use in my experience,
> and that the quotations above show to my satisfaction
> that the post from Kris fell into this classification.

I agree that this is "flaming".
But I also think that Andrei's behavior is "trolling".

> I recognize Kris as a valued contributor to this
> community, and hope that these notes can be taken in
> a constructive spirit.  I'm just an interested party
> here, not trying to lay down the law -- but I've seen
> a fair number of newsgroup discussions and have some
> claim to an understanding of some of the problems
> that can arise and how to avoid them.

I also think that Kris is a valued contributor.
I just don't understand why Andrei is against Tango.
He surely has its motivations, but I don't see them.

Ciao
March 30, 2007
Derek Parnell wrote:
[...]
> This would mean that the sequence example given by Kris ...
> 
>     Cout ("Please enter your name: ").flush;
>     Cout ("Hello, ") (Cin.get);
> 
> gets transformed in to 
> 
>     flush( opCall( Cout, "Please enter your name: "));
>     opCall( opCall( Cout, "Hello, "), get(Cin));
> 
> The first statement will end up displaying the text on the console, leaving
> the cursor to the right of the ':' character. Now if the 'get' is called
> next, the user types in her name, say "mavis" and the screen will show ...
> 
>   Please enter your name: mavis
>   _
> 
> and then the inner 'opCall' is run which will show (assuming a flush) ...
> 
>   Please enter your name: mavis
>   Hello, mavis
>   _

Right, but you are assuming a flush() call that is missing (see below).

> 
> However, if the inner 'opCall' is called first the screen will show ...
> 
>   Please enter your name: Hello, _
>
> and the user types in her name and we get ...
> 
>   Please enter your name: Hello, mavis
>   mavis
>   _

No, you are again assuming a flush() call. As Kris explained, the example works only because of buffering: no flush() is called, so the "Hello, " string stays in the output buffer until the Cin.get() call flushes it.

The example works with every order of evaluation, if and only if the output buffer length is equal or greater than the length of the string "Hello, ".

> So the order is reasonable important to sort out.
> 
> Being the conservative procedural type of coder, I would have probably have
> coded ...
> 
>     char[] userName;
>     Cout ("Please enter your name: ").flush;

This flush() call is unneeded.

>     userName = Cin.get();
>     Cout ("Hello, ");
>     Cout (userName);
>     Cout.flush;
>
> Actually, now that I think about it, I'd really do ...
> 
>     char[] userName;
>     char[] myResponse;
> 
>     Cout ("Please enter your name: ");
>     Cout.flush;
>     userName = Cin.get();
>     myResponse = std.string.format("Hello, %s\n", userName);
>     Cout.( myResponse );
>     Cout.flush;
> 
> That is of course, if I'd really used stdin/stdout in that manner at all
> <G>

<G>

Ciao
March 30, 2007
James Dennett wrote:
[snip]
> Now, please just accept that I consider such attacks on
> a person to be inappropriate, that they meet definitions
> of "flaming" that are in common use in my experience,
> and that the quotations above show to my satisfaction
> that the post from Kris fell into this classification.

That's cool, James.

You'll also please just accept that I'll sometimes call things as I see them? I've seen Andrei make "attacks" upon others, I've witnessed the manner in which he operates, and I've been the recipient of his 'distaste' on several occasions.

It's not in my interest to take issue with anyone in particular, yet I don't have much patience for stupid games either, particularly when there's the smell of an agenda in the air. I called Andrei out, and you don't like the way I approached it. I can, and will, happily accept that. And, I do appreciate you stepping up and speaking your mind too.

If you'd like further clarification, I'd be glad to discuss it offline.


> I recognize Kris as a valued contributor to this
> community, and hope that these notes can be taken in
> a constructive spirit.  I'm just an interested party
> here, not trying to lay down the law -- but I've seen
> a fair number of newsgroup discussions and have some
> claim to an understanding of some of the problems
> that can arise and how to avoid them.

Yes, I fully agree
March 30, 2007
Derek Parnell wrote:
> On Thu, 29 Mar 2007 22:40:34 -0700, 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.). 
> 
> Now that makes sense. I can see now why the W&A show is concerned. In fact,
> the call-chaining example seems to flesh out to ...
> 
>    opCall(opCall(Cout,"Hello, "), get(Cin));
> 
> which means that either the 'get' could be called first or the inner
> 'opCall' could be called first. One can never be sure.
> 
> This would mean that the sequence example given by Kris ...
> 
>     Cout ("Please enter your name: ").flush;
>     Cout ("Hello, ") (Cin.get);
> 
> gets transformed in to 
> 
>     flush( opCall( Cout, "Please enter your name: "));
>     opCall( opCall( Cout, "Hello, "), get(Cin));
> 
> The first statement will end up displaying the text on the console, leaving
> the cursor to the right of the ':' character. Now if the 'get' is called
> next, the user types in her name, say "mavis" and the screen will show ...
> 
>   Please enter your name: mavis
>   _
> 
> and then the inner 'opCall' is run which will show (assuming a flush) ...
> 
>   Please enter your name: mavis
>   Hello, mavis
>   _
> 
> 
> However, if the inner 'opCall' is called first the screen will show ...
> 
>   Please enter your name: Hello, _
> 
> and the user types in her name and we get ...
> 
>   Please enter your name: Hello, mavis
>   mavis
>   _
> 
> 
> So the order is reasonable important to sort out.
> 
> Being the conservative procedural type of coder, I would have probably have
> coded ...
> 
>     char[] userName;
>     Cout ("Please enter your name: ").flush;
>     userName = Cin.get();
>     Cout ("Hello, ");
>     Cout (userName);
>     Cout.flush;
> 
> Actually, now that I think about it, I'd really do ...
> 
>     char[] userName;
>     char[] myResponse;
> 
>     Cout ("Please enter your name: ");
>     Cout.flush;
>     userName = Cin.get();
>     myResponse = std.string.format("Hello, %s\n", userName);
>     Cout.( myResponse );
>     Cout.flush;
> 
> That is of course, if I'd really used stdin/stdout in that manner at all
> <G>
> 

I'd do something like...

import tango .io .Console ;
import tango .io .Stdout  ;

char[] userName ;

Stdout ("Please enter your name: "c) .flush ;
userName = Cin.get();
Stdout .formatln("Hello, {}.", userName) .flush ;


That's closer to my usage patterns with Tango.  (I'm a bigger fan of Stdout than Cout in most cases, partly because I use plenty of format strings.)

-- Chris Nicholson-Sauls
March 30, 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@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
March 30, 2007
John Reimer wrote:
> On Thu, 29 Mar 2007 21:59:49 -0700, James Dennett wrote:
> 
>> kris wrote:
>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>> kris wrote:
>>>>
>>>>> Frits van Bommel wrote:
>>>>>
>>>>>> Yes, call-chaining can only evaluate left-to-right, but the
>>>>>> parameters *passed* to the calls can be evaluated in any order.
>>>>>
>>>>> That's not at stake here, as far as I'm aware?
>>>>
>>>> My understanding is that it was brought up by yourself in an attempt
>>>> to explain that Cout("Hello, ")(Cin.get) will work properly. There was
>>>> an old thread mentioned, which deals with another problem entirely. So
>>>> that doesn't apply. Now I understand that argument has been dropped
>>>> entirely, and that now there is an argument that Cout("Hello,
>>>> ")(Cin.get) works due to some other unmentioned reasons.
>>> Then I politely suggest you are either badly confused, being entirely
>>> disengeneous, or are drunk ;-)
>>>
>>> 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.
>>
>> Please, just address the technical content rather than
>> flaming.
>>
>> -- James
> 
> 
> I disagree with your strange assertion that Kris is flaming. After following Andrei's posts, I tend to agree with Kris' perspective.
> 
> Andrei does come across as having an agenda.  I can accept that given his
> position in the influence of D; but it's becoming very hard to separate
> truth from perspective in all these posts.  Why is it wrong to state that
> Andrei has an agenda?  He does, doesn't he?  Are we all afraid to admit it?
> I just don't think he's going about it very honestly. If he were trully
> seeking to be helpful to Tango design ideas, he would be contributing over
> in the Tango forums... Since he doesn't do that, it's quite easy to see
> why one might think he has an agenda... and not in Tango's favour.
> 
> Andrei does tend to push his preferences on the community. That
> deserves to be balanced.  Kris, Sean, and others have been doing their best
> to be clear and fair in regards to addressing Tango "propaganda"; if
> Andrei makes allegations about Tango, they are obligated to
> either defend design decisions or accept recommendations as feasible and
> beneficial.  I think they've been doing a very good job of both given the
> circumstances.  Are people not noticing this? 
> 
> I don't recall ever seeing Andrei admit he is wrong without some
> equivication or deflection. If he does, it's often hidden in some sorty
> joke or distraction. He's just not a straight forward person, plain and
> simple.  Either that or he has trouble with humility.
> 
> He's got oodles of creativity, good ideas, experience... and personal
> opinions (like many here) and maybe even a little bit of academic rigour to
> back him up :). He makes tons of :O) faces. But these matter little, if he
> serves his own preferences, his own interests, and his own agenda.  Maybe
> I got him wrong, but from what I've seen, I doubt it.

The only civilized response I can imagine to this is killfiling sender's address. It's understandable for anyone to get heated and make a few ad hominem arguments in the midst of a heated argument. But to actually sit down and build an entire web of assumptions leading to sweeping personality judgments, that's just shady. Put yourself for a minute at the receiving end of such calumny and you'll understand why you ought to be ashamed of yourself.


Andrei