www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - It's a dead horse but I still need it to go... (opAssign)

reply Traveler Hauptman <th barrett.com> writes:
I do embedded/real-time programming for robotics. I like the D language and
have 
been playing with a vector/matrix math class. With vanilla code (no assembler) 
and standard optimization it is 5 times faster than equivalent vanilla C++ code 
and 3 times faster than C. It does not use the built in garbage collector, 
rather what walter calls a fast-stack. It's everything I wished I had...

Except my code reads:
{
   Vect a = new Vect(6);
   Vect b = new Vect(6);

   a.fill(1.0);
   b.fill(2.0);

   b.assign( c + 2.0 * a + a * b + 10.0);
}

To be so close to nirvana and without an opAssign()... I want to cry.


Just wanted to share my misery...

Traveler
Nov 19 2005
next sibling parent Factory <t t.com> writes:
In article <dlo5mc$17oh$1 digitaldaemon.com>, 
th barrett.com says...
 Except my code reads:
 {
    Vect a = new Vect(6);
    Vect b = new Vect(6);
 
    a.fill(1.0);
    b.fill(2.0);
 
    b.assign( c + 2.0 * a + a * b + 10.0);
 }
 
 To be so close to nirvana and without an opAssign()... I want to cry.

Hmm I just use a static function called ctor(). ie struct Vect { static Vect ctor( int _x, int _y ) { Vect v; v.x= _x; v.y= _y; return v; } ... }; Which isn't perfect, but it's pretty close. Vect v= Vect.ctor( 0,0 ) + Vect.ctor( 1,1 ) compared to Vect v= Vect( 0,0 ) + Vect( 1,1 ) (But then again I merge all my .d files into one before compiling to get around the (IMHO unusable) module system, so I'm no guru :) ) - Factory
Nov 19 2005
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Sat, 19 Nov 2005 16:34:44 -0500, Traveler Hauptman wrote:

 
 Just wanted to share my misery...

Thanks. Its like having $300 customized running shoes that do the perfect job, but constantly finding little pebbles in them. Not have an 'op'_something_or_other_name that gets called when the form classinstance = something; is so frustrating. I still fail to see the overriding, blinding obvious, reason for not having it. -- Derek Parnell Melbourne, Australia 20/11/2005 5:29:08 PM
Nov 19 2005
parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
In article <1ol6gofhwkngq.18oz5jfsrgka$.dlg 40tude.net>, Derek Parnell says...
On Sat, 19 Nov 2005 16:34:44 -0500, Traveler Hauptman wrote:

 
 Just wanted to share my misery...

Thanks. Its like having $300 customized running shoes that do the perfect job, but constantly finding little pebbles in them. Not have an 'op'_something_or_other_name that gets called when the form classinstance = something; is so frustrating. I still fail to see the overriding, blinding obvious, reason for not having it.

I fully agree that not having assignment overloading is severely limiting. One reason may be that classes are reference types. If classes started overriding opAssign, you would have to resort to pointers to classes to make pure references. There is one middle road though: Allow copy/assignment overloading for structs. Considering the value based nature of structs, this feels very natural. If this was possible, you could even wrap the class reference in a struct if you needed custom assignment semantics. /Oskar
Nov 20 2005
parent reply Ben Phillips <Ben_member pathlink.com> writes:
I fully agree that not having assignment overloading is severely limiting. One
reason may be that classes are reference types. If classes started overriding
opAssign, you would have to resort to pointers to classes to make pure
references.

http://www.digitalmars.com/d/class.html You are correct. "Class objects are instantiated by reference only." This makes the possibility of creating an assignment operator virtually impossible. How would you tell whether the user wants to assign by reference or by value (how can you even assign by value when you only have references?)?
Nov 21 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 21 Nov 2005 23:08:53 +0000 (UTC), Ben Phillips wrote:

I fully agree that not having assignment overloading is severely limiting. One
reason may be that classes are reference types. If classes started overriding
opAssign, you would have to resort to pointers to classes to make pure
references.

http://www.digitalmars.com/d/class.html You are correct. "Class objects are instantiated by reference only." This makes the possibility of creating an assignment operator virtually impossible. How would you tell whether the user wants to assign by reference or by value (how can you even assign by value when you only have references?)?

So the limitation is that we only have /one/ assignment operator available for us to use, even though we have /two/ types of assignments possible: copying references, and copying values. I've assumed that the standard convention for copying value is the dup() method, as in ... Foo a = new Foo(4); Foo b = new Foo; b = a.dup(); A new assignment operator that *only* means copy value might be a useful addition then. b := a; regardless of whether 'a' and 'b' are classes, structs, or native types. In all cases the coders is asking the compiler to copy values. For structs and classes it would call the opCopyValue() method if defined otherwise fail. So ... b := a; would be that same as b.opCopyValue(a); which allows for overloading possibilities for different data types. In the case of native types it would be exactly equivalent to the current '=' operator. -- Derek (skype: derek.j.parnell) Melbourne, Australia 22/11/2005 10:40:48 AM
Nov 21 2005
next sibling parent Ben Phillips <Ben_member pathlink.com> writes:
In article <1mfot7cqsdo1x$.1hbjalv1cpfbb.dlg 40tude.net>, Derek Parnell says...
On Mon, 21 Nov 2005 23:08:53 +0000 (UTC), Ben Phillips wrote:

I fully agree that not having assignment overloading is severely limiting. One
reason may be that classes are reference types. If classes started overriding
opAssign, you would have to resort to pointers to classes to make pure
references.

http://www.digitalmars.com/d/class.html You are correct. "Class objects are instantiated by reference only." This makes the possibility of creating an assignment operator virtually impossible. How would you tell whether the user wants to assign by reference or by value (how can you even assign by value when you only have references?)?

So the limitation is that we only have /one/ assignment operator available for us to use, even though we have /two/ types of assignments possible: copying references, and copying values. I've assumed that the standard convention for copying value is the dup() method, as in ... Foo a = new Foo(4); Foo b = new Foo; b = a.dup(); A new assignment operator that *only* means copy value might be a useful addition then. b := a; regardless of whether 'a' and 'b' are classes, structs, or native types. In all cases the coders is asking the compiler to copy values. For structs and classes it would call the opCopyValue() method if defined otherwise fail. So ... b := a; would be that same as b.opCopyValue(a); which allows for overloading possibilities for different data types. In the case of native types it would be exactly equivalent to the current '=' operator. -- Derek (skype: derek.j.parnell) Melbourne, Australia 22/11/2005 10:40:48 AM

Thats the best idea I've heard, though it might be easy to mistake ":=" for "=" when skimming over code.
Nov 21 2005
prev sibling next sibling parent traveler hauptman <traveler_member pathlink.com> writes:
In article <1mfot7cqsdo1x$.1hbjalv1cpfbb.dlg 40tude.net>, Derek Parnell says...
<snip>
So the limitation is that we only have /one/ assignment operator available
for us to use, even though we have /two/ types of assignments possible:
copying references, and copying values.

I've assumed that the standard convention for copying value is the dup()
method, as in ...

   Foo a = new Foo(4);
   Foo b = new Foo;
   b = a.dup();


A new assignment operator that *only* means copy value might be a useful
addition then. 

   b := a;

regardless of whether 'a' and 'b' are classes, structs, or native types. In
all cases the coders is asking the compiler to copy values. For structs and
classes it would call the opCopyValue() method if defined otherwise fail. 

So ...
   b := a;
would be that same as 
   b.opCopyValue(a);

which allows for overloading possibilities for different data types.

In the case of native types it would be exactly equivalent to the current
'=' operator.

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
22/11/2005 10:40:48 AM

It's a bit late for it now but it was a curious decision to have class declarations be different than all others: void*,int* vs class* <- Screwed me up for a while. '=' works fine without needing another operator if your syntax is consistent. (*foo = *bar; foo = bar;) Compile time type checking will catch any errors. Perhaps restating what Derek is saying, it would be interesting to consistently seperate assignment for values and assignment for references. So it would be obvious when an expression is working with pointers vs working with the object itself. double* a,b; double c,d; a := &c; b := a; c = d; c = *a; a := c; <- illegal c = a; <- illegal Traveler Hauptman www.barrett.com
Nov 21 2005
prev sibling next sibling parent Georg Wrede <georg.wrede nospam.org> writes:
Derek Parnell wrote:
 On Mon, 21 Nov 2005 23:08:53 +0000 (UTC), Ben Phillips wrote:
 
 I fully agree that not having assignment overloading is
 severely  limiting. One reason may be that classes are
 reference types. If classes started  overriding opAssign,
 you would have to resort to pointers to classes to make
 pure references.

http://www.digitalmars.com/d/class.html You are correct. "Class objects are instantiated by reference only." This makes the possibility of creating an assignment operator virtually impossible. How would you tell whether the user wants to assign by reference or by value (how can you even assign by value when you only have references?)?

So the limitation is that we only have /one/ assignment operator available for us to use, even though we have /two/ types of assignments possible: copying references, and copying values. I've assumed that the standard convention for copying value is the dup() method, as in ... Foo a = new Foo(4); Foo b = new Foo; b = a.dup(); A new assignment operator that *only* means copy value might be a useful addition then. b := a; regardless of whether 'a' and 'b' are classes, structs, or native

 all cases the coders is asking the compiler to copy values. For

 classes it would call the opCopyValue() method if defined otherwise
 fail.
 
 So ...
    b := a;
 would be that same as 
    b.opCopyValue(a);
 
 which allows for overloading possibilities for different data types.
 
 In the case of native types it would be exactly equivalent to the
 current '=' operator.

You know, that sounds really intriguing!
Nov 21 2005
prev sibling parent =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak invalid_utu.fi> writes:
Derek Parnell wrote:
 I've assumed that the standard convention for copying value is the dup()
 method, as in ...
 
    Foo a = new Foo(4);
    Foo b = new Foo;
    b = a.dup();
 
 A new assignment operator that *only* means copy value might be a useful
 addition then. 
 
    b := a;
 
 regardless of whether 'a' and 'b' are classes, structs, or native types. In
 all cases the coders is asking the compiler to copy values. For structs and
 classes it would call the opCopyValue() method if defined otherwise fail. 
 
 So ...
    b := a;
 would be that same as 
    b.opCopyValue(a);
 
 which allows for overloading possibilities for different data types.
 
 In the case of native types it would be exactly equivalent to the current
 '=' operator.
 

I think this has been discussed before, but someone didn't like the Pascal-style syntax ":=". It would be cool to have at least some kind of user-controlled shallow/deep-copy operator for classes. Somehow := looks a lot nicer than a copy constructor or foo.clone().
Nov 29 2005
prev sibling next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Traveler Hauptman wrote:

 but I still need it to go... (opAssign)

Where is the need? Or more detailed: why a class instead of a struct? -manfred
Nov 20 2005
parent reply Traveler Hauptman <th barrett.com> writes:
Manfred Nowak wrote:
 Traveler Hauptman wrote:
 
 
but I still need it to go... (opAssign)

Where is the need? Or more detailed: why a class instead of a struct? -manfred

I am not looking for a "copy contents on assign"; Because I cannot use the garbage collector and malloc is too slow; I have a specialized memory manager for my Vector/Matrix class. On "assignment" I clean up the calculation stack. In debug/profile mode I also collect calculation statistics. -traveler
Nov 20 2005
next sibling parent JT <JT_member pathlink.com> writes:
In article <dlq9ge$2sq3$1 digitaldaemon.com>, Traveler Hauptman says...
Manfred Nowak wrote:
 Traveler Hauptman wrote:
 
 
but I still need it to go... (opAssign)

Where is the need? Or more detailed: why a class instead of a struct? -manfred

I am not looking for a "copy contents on assign"; Because I cannot use the garbage collector and malloc is too slow; I have a specialized memory manager for my Vector/Matrix class. On "assignment" I clean up the calculation stack. In debug/profile mode I also collect calculation statistics. -traveler

Maybe you could use one of the other ops you arent using like the ~= cat op. Wouldnt it be ironic if in walters desire to make the code less obfuscated people worked around his limitations and in fact made it more obfuscated. Im afraid that in some cases this will be the result. I would love an opAssign, and Im hoping to just implment one via a compile time metaobject protocol, where a modified D front end will simply replace all instances of x = y with x.opAssign(y) and sends it to the DMD compiler. So in the end I dont really mind. Walter has made the language so easy to parse that extending the laguage is fairly simple.
Nov 20 2005
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Traveler Hauptman wrote:

[...]
 On "assignment" I clean up the calculation stack. In
 debug/profile mode I also collect calculation statistics.

I see. Now please explain, what should happen with expressions like x= y= b= c= c + 2.0 * a + a * b + 10.0; Especially if x and y are of types derived from your vector class? Are you able to present a homogene solution under all aspects? -manfred
Nov 20 2005
next sibling parent Derek Parnell <derek psych.ward> writes:
On Sun, 20 Nov 2005 23:00:30 +0000 (UTC), Manfred Nowak wrote:

 Traveler Hauptman wrote:
 
 [...]
 On "assignment" I clean up the calculation stack. In
 debug/profile mode I also collect calculation statistics.

I see. Now please explain, what should happen with expressions like x= y= b= c= c + 2.0 * a + a * b + 10.0; Especially if x and y are of types derived from your vector class? Are you able to present a homogene solution under all aspects?

Yes. Assuming that 'homogene solution' in this context means 'solution that works as expected'. -- Derek Parnell Melbourne, Australia 21/11/2005 1:00:46 PM
Nov 20 2005
prev sibling parent Traveler Hauptman <th barrett.com> writes:
Manfred Nowak wrote:
 Traveler Hauptman wrote:
 
 [...]
 
On "assignment" I clean up the calculation stack. In
debug/profile mode I also collect calculation statistics.

[...] I see. Now please explain, what should happen with expressions like x= y= b= c= c + 2.0 * a + a * b + 10.0; Especially if x and y are of types derived from your vector class? Are you able to present a homogene solution under all aspects? -manfred

Let me preface by saying I do not have any experience with inheritance. Assign (no pun intended) credibility as you will. I think you are asking what the super level copy/cleanup will do when it is called with no overloaded copy/cleanup of it's own? Yes, it will NOT work. But why does that matter? Most classes will need this(){} methods and if they don't; it's assumed you want defalt values assigned. Derived classes, as I understand it, will have this(){mythis();super();}. So for value copy from one location to another (opAssign) defalt to moving the values as you would a struct. If that doesn't do it for you then void opAssign(){myopAssign();super.opAssign();} should do the trick? IMO the power of classes is that they are an opportunity to teach the computer a new type. Types have: *Memory allocation/deallocation (new/delete) <- Well done in D (Except for the dependance of the std lib on the GC) *Initialization/Cleanup (this/~this) <- The addition of (type x = void;) brought it all together. *Value copy (double a,b; a =b;) <- not well done in D *Collection access (double* a;double[4] b; a++; a = a + a.sizeof;*a = b[2];) <- You can overload the operators if you need it. *Temporary storage for compound expressions (a = b + c + d;) <- What led me to use my own calculation stack... The Computer scientists out there can add to the list... D is a great language. I represent the enormous population of high performance robotics programmers. ;) I would love to use D instead of C. It's so close... But I can't use it yet. -traveler
Nov 21 2005
prev sibling parent Nick <Nick_member pathlink.com> writes:
In article <dlo5mc$17oh$1 digitaldaemon.com>, Traveler Hauptman says...
Except my code reads:
{
   Vect a = new Vect(6);
   Vect b = new Vect(6);

   a.fill(1.0);
   b.fill(2.0);

   b.assign( c + 2.0 * a + a * b + 10.0);
}

To be so close to nirvana and without an opAssign()... I want to cry.

Why isn't there an opSliceAssign operator? Seems to fit naturally with the opIndex/opIndexAssign operators. It would at least allow you to write b[] = c + 2.0*a + a*b + 10.0; which IMO would make MORE sense than opAssign in your case, since you are not simply overwriting the b reference but doing something to the contents of b. (Just like the difference between "a = ..." and "a[] = ..." in normal D arrays.) Nick PS: As a crude hack you could always make an void opIndexAssign(Vect v, int dummy) { assign(v); } and write b[0] = c + ..., but it's not terribly nice :)
Nov 20 2005