View mode: basic / threaded / horizontal-split · Log in · Help
December 14, 2006
Re: DMD 0.177 release
Kevin Bealer wrote:
>
> == Quote from Andrei Alexandrescu (See Website For Email)
> (SeeWebsiteForEmail@erdani.org)'s article
>>
>> Here's a better alternative:
>> Require opAssign() to always return void and have the compiler return a
>> reference to the left-hand side. That is, transform:
>> a = b;
>> into:
>> (a.opAssign(b), a);
>> with the mention that a only gets evaluated once.
>> This way assignment _always_ returns its left-hand side and user code
>> cannot subvert that behavior. Also the code will be efficient because no
>> more spurious copies are being made.
> 
> I wonder, are there cases where assignment should not return 'this'?

I've been thinking the same thing, and so far haven't been able to come 
up with an example where "correct" use of an assignment operator should 
not return 'this'.  I was considering suggestion the same thing as 
Andrei above, but was hoping someone would post a counterexample in the 
interim :-)  About the only weird thing with returning void and allowing 
this:

    a = b = c;

Is that it isn't equivalent to this:

    a.opAssign( b.opAssign( c ) );

Which may be a bit confusing.  But it does seem quite natural that the 
result of an assignment should always be the LHS of the assignment.


Sean
December 14, 2006
Re: DMD 0.177 release
Jarrett Billingsley schrieb:
> "Walter Bright" <newshound@digitalmars.com> wrote in message 
> news:elnv14$r2d$1@digitaldaemon.com...
> 
>> For whatever the merits of opCall vs this(), efficiency is NOT a problem 
>> with either, and is not a reason to choose one or the other. The generated 
>> code is the same.
>>
>> Under the hood, they are the same. Both take a hidden pointer to where the 
>> result is stored. The rest is window dressing.
> 
> Alright then.  All I've got then is the orthogonality argument.  But you 
> won't listen to that either.
> 
> People will come to D from C++ and C# and ask "where are constructors in 
> structs?" and we'll say "you have to use static opCall."  And they'll ask 
> "why?"  And all we'll be able to do is shake our heads, sigh, and say "I 
> don't know."
> 
> For the last time, even though you don't care: we have been using static 
> opCall as a WORKAROUND.  As in *we never intended for that to be the 
> canonical method of constructing a struct*.  I don't think anyone would 
> complain if they were given a consistent, logical method of initializing any 
> aggregate type. 
> 
> 

To me another big problem is the cast to a struct. How could anyone, who 
is new to D/ didn't study the spec enough expect, that a cast to a 
struct is done by calling the "opCall". One of those who came from C++ 
(like me too) would expect the static opCall as the equivalent to those 
rather rarely used C++-operator()() overloads.
What could one answer if some of them ask why it's like this? Couldn't 
there just be another name than static opCall?

Then, to keep it from being ambigous, there could be a change of the 
let's say opCreate syntax. It doesn't has to be like in C++, I imagine 
something in the direction of static struct initializers:

struct A
{
	int i, j;
}

int v = 9;
A a = A:{a:10, j:v /*not only constants*/};
December 14, 2006
Re: DMD 0.177 release
Lionello Lunesu wrote:
> Walter Bright wrote:
>> It is possible to force the return type of opAssign. But I'd suggest 
>> making it an S*, with the rewrite to:
>>
>>     *(a.opAssign(b))
>>
> 
> class C {
>   C* opAssign(...) {...}
> }
> struct S {
>   S* opAssign(...) {...}
> }
> 
> Seriously?? Ugh.

It isn't necessary for classes, as they are already reference types.

> Why not just "C opAssign" and "S opAssign"? In the opCall discussion you 
> said yourself that the return value will be optimized.
> 
> Am I missing something?

Yes. The issue is that opAssign has both a return value *and* copies 
values into it's 'this' pointer.
December 14, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> Stewart Gordon wrote:
<snip>
>> The programmer would have a choice - opAssign returning void to modify 
>> in-place the object referenced by the lvalue, or returning a new 
>> object that will be assigned to the lvalue.  What is this precluding?
> 
> opAssign has 3 externally visible characteristics:
> 
> 1) the parameter
> 2) the 'this' pointer
> 3) the return value
> 
> Your proposal mixes up 2 and 3. opAssign works like:
> 
>     a = b
> becomes:
>     a.opAssign(b)
> 
> The return value is not assigned to a, it is the value of the expression 
> (a = b). Mixing up the return value and the assignment to a will cause 
> problems, as the two are different things, and should be independent.

C'mon, what's your use case for being allowed to return something other 
than the new value of a from the expression (a = b)?

Stewart.
December 14, 2006
Re: DMD 0.177 release
Stewart Gordon wrote:
> C'mon, what's your use case for being allowed to return something other 
> than the new value of a from the expression (a = b)?

I don't have one. But I prefer to impose as few restrictions as 
possible, as people keep finding unanticipated cool new things to do. So 
I'd argue that there should be compelling case put forward to impose 
such a restriction, rather than wondering what one can do with the 
flexibility.
December 14, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> Stewart Gordon wrote:
>> C'mon, what's your use case for being allowed to return something 
>> other than the new value of a from the expression (a = b)?
> 
> I don't have one. But I prefer to impose as few restrictions as 
> possible, as people keep finding unanticipated cool new things to do. So 
> I'd argue that there should be compelling case put forward to impose 
> such a restriction, rather than wondering what one can do with the 
> flexibility.

For one, it might be useful to return some sort of proxy for 'a'.

--bb
December 15, 2006
Re: DMD 0.177 release
Lionello Lunesu wrote:
> Walter Bright wrote:
>> It is possible to force the return type of opAssign. But I'd suggest 
>> making it an S*, with the rewrite to:
>>
>>     *(a.opAssign(b))
>>
> 
> class C {
>   C* opAssign(...) {...}
> }
> struct S {
>   S* opAssign(...) {...}
> }
> 
> Seriously?? Ugh.
> 
> Why not just "C opAssign" and "S opAssign"? In the opCall discussion you 
> said yourself that the return value will be optimized.
> 
> Am I missing something?

There is no *extra* copying, in the sense that exactly one copy is done. 
But most of the time the copy obtained is not used, in which case that 
one copy is spurious.


Andrei
December 15, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Require opAssign() to always return void and have the compiler return 
>> a reference to the left-hand side. That is, transform:
>>
>> a = b;
>>
>> into:
>>
>> (a.opAssign(b), a);
>>
>> with the mention that a only gets evaluated once.
>>
>> This way assignment _always_ returns its left-hand side and user code 
>> cannot subvert that behavior. Also the code will be efficient because 
>> no more spurious copies are being made.
> 
> It is possible to force the return type of opAssign. But I'd suggest 
> making it an S*, with the rewrite to:
> 
>     *(a.opAssign(b))

Makes sense, but then I keep on racking my brain to ever think of any 
C++ code that ever return something else than *this. Never saw any, 
never wrote any - ever.

So I just conclude that customizing =, +=, -= etc. is a good thing, but 
customizing their return type and value is not. Adding the silly "return 
this;" litany at the end of every single operator is not something for a 
language that wants to do things the right way. The speed will be 
better, too. It's kind of annoying to know that I can't write:

a = b;

and simply have the compiler do what it takes and no more. Every of 
those spurious copies is just some more discomfort I have to put in.


Andrei
December 15, 2006
Re: DMD 0.177 release
Walter Bright wrote:
>> Why not just "C opAssign" and "S opAssign"? In the opCall discussion 
>> you said yourself that the return value will be optimized.
>>
>> Am I missing something?
> 
> Yes. The issue is that opAssign has both a return value *and* copies 
> values into it's 'this' pointer.

This is wrong. The assignment should return an lvalue, and the current 
semantics of opAssign do not allow that. Here is some code:

void Increment(inout int x) {
  ++x;
}

int a;
Increment(a = 5);

This code leaves a containing the value 6. This is because a is first 
assigned a 5, then a is passed __as an lvalue__ to Increment, which 
bumps it.

Now consider:

struct S {
  int a;
  S opAssign(int x) {
    a = x;
    return this;
  }
}

void Increment(inout S x) {
  ++x.a;
}

S a;
Increment(a = 5);

This is going to have very different (and useless and unwanted) semantics.

Again, the right thing to do: give the Caesar what belongs to the 
Caesar. Have the user do the assignment (and return void), and have the 
compiler pass the lhs lvalue around, when needed.


Andrei
December 15, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> Stewart Gordon wrote:
>> C'mon, what's your use case for being allowed to return something 
>> other than the new value of a from the expression (a = b)?
> 
> I don't have one. But I prefer to impose as few restrictions as 
> possible, as people keep finding unanticipated cool new things to do. So 
> I'd argue that there should be compelling case put forward to impose 
> such a restriction, rather than wondering what one can do with the 
> flexibility.

Just did so in my previous post.

Andrei
10 11 12 13 14 15 16 17 18
Top | Discussion index | About this forum | D home