April 06, 2005
On Wed, 06 Apr 2005 16:57:02 -0400, David Medlock wrote:

> Overloading assignment is a semantic minefield to say the least, and has come up here before (Google this newsgroup).
> 
> 
> Redefining the assignment operator would cripple vectorization efforts, judging by the recent move towards 'static-single-assignment', such as in GCC 4.x, also SAC( single assignment C).
> 
> Since assignment might mean assignment and other times mean a method call, its hard to convert it to an intermediate SSA representation.
> 
> Two viable options :
> 
> - Use the overloaded opCall() which takes different types depending on
> what you need.
> - Convince Walter to allow a := operator which would throw NullPointer
> if the recipient is null or not a variable.

Currently, I have this concept implemented as a property of the 'receiving' class. eg.

 class Foo
 {
   void Value( Bar x) { . . . }
 }

  Foo a = new Foo;
  Bar b = new Bar;
  . . .
  a.Value = b;

However, I have two problems with this. The first problem is that I occasionally forget that I'm dealing with classes and code " a = b ", because it feels natural to code that when transferring value from one thing to another, but I get rewarded with an error message about implicit casting. Secondly, it makes designing a single template that covers all data types impossible. I need to have one template for classes and another for intrinsic types, simply because I can't use "a = b" for both situations.

Thank you all for this enlightening discussion. I've learned lots from it, but I can't actually see Walter doing anything about this, even in v2.0, so I'll drop it and blunder on.

-- 
Derek Parnell
Melbourne, Australia
7/04/2005 7:21:18 AM
April 07, 2005
On Thu, 07 Apr 2005 08:45:21 +1200, <brad@domain.invalid> wrote:
> rter syntax:
>>  class T { T opShlAssign(Foo c) { /*...*/ return this; } }
>>  a<<=b; // almost like a=b, if you ask me
>>  I guess in 99.99999% cases, shifting an object to left with another object doesn't make sense anyway, so the operator might as well get another use..
>>   xs0
>
> Argh!  Surely not!  I thought one of the philosophies of D was that operators should _always_ do what you expect.  The <<= operator should always shift left & assign.
>
> Derek - am I right in saying that you want an assignment operator that doesn't create a new object, but instead alters an existing one?  At the moment, when you deal with objects/references, the = operator always means "set this reference to this object".  I don't think that it makes sense to overload this meaning, because you then end up with an operator that in some cases does
> "set this reference to this object" and in other cases
> "alter the internal data layout of object A, based on the values in object B"
> And then you end up with a whole lot of special rules to try and remember which assignment operator is applying.  Overwriting the contents of an object when you really ment to assign to a new object could ruin your day if you hold multiple references to the object you are stomping on.
>
> I am in favour of having an operator that means "take object B, get some values out of it and setup object A accordingly"

And if they're the same type, it could be used for a "deep-copy"?
I think we can combine this casting concern with the deep-copy concern, they seem closely related to me.

> Something like
> Foo a = new Foo ();
> Bar b = new Bar ();
> a <- b // which calls a.opConvert(b);
>
> I guess you could also end up with nasty
> a = (new Foo())<- b;

It seems 'correct' if 'ugly', done in 2 steps looks nicer and incurs no additional penalty (that I can see).

a = new Foo();
a <- b;

this operator is really a "copy RHS into LHS" operator, which implys that LHS must exists beforehand.
Or using the "<-" operator could implicitly call new if the LHS is null... not sure how feasible that is.

> <- is probably not the operator to choose, probably hard to parse. Maybe someone else can think of a good operator if this functionality is required.

I agree, I think the main concern against this in Walters case was that implicit conversion when "=" is used can cause subtle behaviour and bugs. (correct me if I am wrong).

So, if a new operator was used, eg. ":=" or something then this concern vanishes, as "=" does what it currently does:
 - shallow copy for arrays.
 - reference assignment for classes etc
 - deep copy for value types

The new ":=" operator always means "copy RHS into LHS" AKA:
 - deep copy for arrays (provided items in array have deep-copy method defined)
 - deep copy for classes (provided class has deep-copy method defined)
 - same as "=" for value types.

Thoughts?

Regan
April 07, 2005
On Thu, 07 Apr 2005 13:34:52 +1200, Regan Heath wrote:

[snip]

> So, if a new operator was used, eg. ":=" or something then this concern
> vanishes, as "=" does what it currently does:
>   - shallow copy for arrays.
>   - reference assignment for classes etc
>   - deep copy for value types
> 
> The new ":=" operator always means "copy RHS into LHS" AKA:
>   - deep copy for arrays (provided items in array have deep-copy method
> defined)
>   - deep copy for classes (provided class has deep-copy method defined)
>   - same as "=" for value types.
> 
> Thoughts?

Ok, an additional operator then. So long as 'value types' also includes the
intrinsic data types like int, real, byte, ..., so that we could make
useful templates, I could cope with this.
Thus ...

   int a;

   a = b;
and
   a := b;

would behave identically.

And, we still need to deal with ...

   struct Foo {}
   int a;
   Foo b;

   a := b;

Maybe Walter will allow us to do ...

   void opDeepCopy(inout int X, Foo Y) { ... }

so that " a := b; " would call

   opDeepCopy(a,b);

Also, I'd like to be able to do deep copies for structs too, even though they are 'value' types. Such that ...

   struct Foo {}
   Foo a;

   a := b;  // call a.opDeepCopy(b) or some such.

-- 
Derek Parnell
Melbourne, Australia
http://www.dsource.org/projects/build/ v1.19 released 04/Apr/2005
http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage
7/04/2005 12:06:34 PM
April 07, 2005
> Ok, an additional operator then. So long as 'value types' also includes the
> intrinsic data types like int, real, byte, ..., so that we could make
> useful templates, I could cope with this. Thus ...
> 
>    int a;
> 
>    a = b;
> and
>    a := b;
> 
> would behave identically.
> 
> And, we still need to deal with ...
> 
>    struct Foo {}
>    int a;
>    Foo b;
> 
>    a := b;
> 
> Maybe Walter will allow us to do ...
> 
>    void opDeepCopy(inout int X, Foo Y) { ... }
> 
> so that " a := b; " would call
> 
>    opDeepCopy(a,b);
> 
> Also, I'd like to be able to do deep copies for structs too, even though
> they are 'value' types. Such that ...
> 
>    struct Foo {}
>    Foo a;
> 
>    a := b;  // call a.opDeepCopy(b) or some such.
> 
Forgive me if I ramble a little - just thinking this through.
1) The main point of := is so we can write templated functions that behave well with intrinsics and user defined types, without needing hacks to get them to work.
2) This won't break any new code, and will allow us to be more expressive with D.
3) ":=" represents "deep copy/convert", it may call a function and should be reguarded as a potentially expensive operator
4) ":=" will fail if the LHS is null (or should it resolve to a LHS static opDeepCopy(inout LHS_class x, type RHS) ?)
5) ":=" with intrinsic LHS will call the function opDeepCopy(LHS, RHS)
6) Have two "assignment" operators is potentially confusing - but probably no more than understanding the difference between shallow and deep copy.
7) we not longer need the .dup property?, because we can go
int a[];
int b[];
a := b; // which is a deep copy of b into a

Brad
April 07, 2005
I like the idea about := operator.

May be one can introduce ":" (opColon) binary operator which in expression
a : b evaluates a and b and then returns b.
Then (using general rule about "op=") ":=" (opColonAssign) will mean
deep-copy and be overloadable ?

-- 
          Vladimir
April 07, 2005
On Thu, 07 Apr 2005 14:17:54 +1200, <brad@domain.invalid> wrote:
>> Ok, an additional operator then. So long as 'value types' also includes the
>> intrinsic data types like int, real, byte, ..., so that we could make
>> useful templates, I could cope with this. Thus ...
>>     int a;
>>     a = b;
>> and
>>    a := b;
>>  would behave identically.
>>  And, we still need to deal with ...
>>     struct Foo {}
>>    int a;
>>    Foo b;
>>     a := b;
>>  Maybe Walter will allow us to do ...
>>     void opDeepCopy(inout int X, Foo Y) { ... }
>>  so that " a := b; " would call
>>     opDeepCopy(a,b);
>>  Also, I'd like to be able to do deep copies for structs too, even though
>> they are 'value' types. Such that ...
>>     struct Foo {}
>>    Foo a;
>>     a := b;  // call a.opDeepCopy(b) or some such.
>>
> Forgive me if I ramble a little - just thinking this through.
> 1) The main point of := is so we can write templated functions that behave well with intrinsics and user defined types, without needing hacks to get them to work.
> 2) This won't break any new code, and will allow us to be more expressive with D.
> 3) ":=" represents "deep copy/convert", it may call a function and should be reguarded as a potentially expensive operator
> 4) ":=" will fail if the LHS is null (or should it resolve to a LHS static opDeepCopy(inout LHS_class x, type RHS) ?)
> 5) ":=" with intrinsic LHS will call the function opDeepCopy(LHS, RHS)
> 6) Have two "assignment" operators is potentially confusing - but probably no more than understanding the difference between shallow and deep copy.
> 7) we not longer need the .dup property?, because we can go
> int a[];
> int b[];
> a := b; // which is a deep copy of b into a

This seems a fairly good list of the points so far, plus a few new/reworded ones which I also like.

Regan
April 07, 2005
brad@domain.invalid wrote:
> rter syntax:
> 
>>
>> class T { T opShlAssign(Foo c) { /*...*/ return this; } }
>>
>> a<<=b; // almost like a=b, if you ask me
>>
>> I guess in 99.99999% cases, shifting an object to left with another object doesn't make sense anyway, so the operator might as well get another use..
>>
>>
>> xs0
> 
> 
> Argh!  Surely not!  I thought one of the philosophies of D was that operators should _always_ do what you expect.  The <<= operator should always shift left & assign.

Hmm, that philosophy is good and all, but what would you expect to get from shifting ClassA by ClassB? I just chose this operator because it looks as a left arrow (at least to me), which is exactly what you proposed, and I couldn't think of any other use for it with classes/structs..

<- is no good, though: "a<-3" should be "a < -3", not "a.opConvert(3)"

As for a new operator for this functionality, I don't think it's necessary. a.set(b) is short enough, it is also much more obvious what's happening, and it's also obvious that a can't be null.. if you don't use opCall for other stuff, you can even just use a(b)..


xs0
April 08, 2005
> Hmm, that philosophy is good and all, but what would you expect to get from shifting ClassA by ClassB? I just chose this operator because it looks as a left arrow (at least to me), which is exactly what you proposed, and I couldn't think of any other use for it with classes/structs..
> 
> <- is no good, though: "a<-3" should be "a < -3", not "a.opConvert(3)"
> 
> As for a new operator for this functionality, I don't think it's necessary. a.set(b) is short enough, it is also much more obvious what's happening, and it's also obvious that a can't be null.. if you don't use opCall for other stuff, you can even just use a(b)..
> 
> 
> xs0

Well, to be honest I don't know what to expect from <<= if you override it and make it do things that aren't shift left and assign :)
What if my LHS class is an implementation that can be shifted left?
Anyhow - I think the main reason for having an assignment operator instead of a.set(b), is that for templates you want the template to work for classes and built in primitives.

Brad
1 2 3
Next ›   Last »