www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - struct inheritance, L-value return

reply cschueler <cschueler_member pathlink.com> writes:
A little report on recent tamperings with D.
I often deal with primitive types which are "vector spaces". Examples

* 3D-vectors
* colors
* quaternions
* matrices.

While these are distinct types with distinct operations, they all have in common

that they can add and subtract members of their kin, and multiply them with a
scalar. They also have a zero (neutral) element.
This is what the term vector space is mathematically about.

In the C++ world, I was so annoyed that I had to type the same boilerplate 
stuff over and over again for each of these types that I invented my "vector
space" template system. With this system it is possibly to declare a vector 
space type with minimum effort and have all the basic operations ready
to go.

It seems I cannot port this system to D with the current state of D.
The short story is I need either

- struct inheritance
or
- anonymous unions outside an aggregate in a mixin

I would prefer struct inheritance:

struct field
{
union { ... };
union { ... };
union { ... };
};

struct vectorspace : field
{
// have anonymous unions of "field" injected into this scope    
}

but I since there is no struct inheritance, I tried with mixins

template field
{
union { ... };
union { ... };
union { ... };
};

struct vectorspace
{
mixin field;        
}

But you cannot have anonymous unions outside a struct :/(
So I'm struck at this point.
Moreover, the mixin approach is not feasible because then 
you cannot make field a template parameter.

template( field )
{
struct vectorspace

only seem to work when field is a type, not a mixin.

I would like to weigh in for struct inheritance, since it seems a
trivial thing to allow. C programmers have often done this 
by declaring a variable of the base type as the first member
of the struct. So I was a little surprised that D has no
inheritance for plain data structs.

There is more missing in D that prevents me to port the
system fully:

- explicit return by reference (return an L-value)
- struct constructors

These are not showblockers, but missing them is ugly!
I see from the archives that struct constructors have been 
discussed already, so count me as another vote for struct
constructors here.

The explicit L-value return however I think is an important
concept that is missing with subtle implications. Without it,
user defined types can never be made transparent to 
builtin types. Consider:

int a;
(+a) = 3;

The unary plus operator returns an L-value, so the assignment
can take place. In C++, you can define the unary + operator
to behave the same for your type, by defining both R-value
and L-value operator:

// R-value unary +
const mytype &operator +( const mytype &object )
{ return object; }

// L-value unary +
mytype &operator +( mytype &object )
{ return object; }

In D, you can only do the R-value version.
Jun 12 2006
next sibling parent mclysenk mtu.edu writes:
In article <e6l2mu$1242$1 digitaldaemon.com>, cschueler says...
I would like to weigh in for struct inheritance, since it seems a
trivial thing to allow. C programmers have often done this 
by declaring a variable of the base type as the first member
of the struct. So I was a little surprised that D has no
inheritance for plain data structs.

There is more missing in D that prevents me to port the
system fully:

- explicit return by reference (return an L-value)
- struct constructors

I've had to deal with my share of vector/matrix classes. I personally hate writing the damn things, since they are so tedious. I'd hoped array ops or something like that would provide a native solution, but I don't think it's gonna happen any time soon. Anyway, struct inheritance is a tricky business. I do not think that structs should be able to inherit functions, since that makes them no different than a class, just like they are in C++. A struct should be treated specially, it should not have a virtual function table or any extra run time information like a class does. As for struct constructors, the common tactic is to use opCall, but I agree that some solution involving the 'this' keyword would be more consistent. The current solution is workable, though a bit obscure. I'm a bit uneasy about that whole l-value thing. As a design decision, it seems to violate the design principal of encapsulation. If you absolutely have to write to an object via its return value, you could try returning a pointer. The library I currently use is based on SSE, though the optimization is still incomplete. You can grab it from http://assertfalse.com -Mik
Jun 12 2006
prev sibling parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
cschueler skrev:
 The short story is I need either
 
 - struct inheritance
 or
 - anonymous unions outside an aggregate in a mixin
 
 I would prefer struct inheritance:
 
 struct field
 {
 union { ... };
 union { ... };
 union { ... };
 };
 
 struct vectorspace : field
 {
 // have anonymous unions of "field" injected into this scope    
 }
 
 but I since there is no struct inheritance, I tried with mixins
 
 template field
 {
 union { ... };
 union { ... };
 union { ... };
 };
 
 struct vectorspace
 {
 mixin field;        
 }
 
 But you cannot have anonymous unions outside a struct :/(
 So I'm struck at this point.

Try adding an anonymous struct to the template: template field() { struct { union {...} union {...} union {...} } }
 Moreover, the mixin approach is not feasible because then 
 you cannot make field a template parameter.
 
 template( field )
 {
 struct vectorspace
 
 only seem to work when field is a type, not a mixin.

Try using an alias parameter: struct vectorspace(alias field) { mixin field; }
 I would like to weigh in for struct inheritance, since it seems a
 trivial thing to allow. C programmers have often done this 
 by declaring a variable of the base type as the first member
 of the struct. So I was a little surprised that D has no
 inheritance for plain data structs.

I agree that struct inheritance would be useful.
 There is more missing in D that prevents me to port the
 system fully:
 
 - explicit return by reference (return an L-value)
 - struct constructors
 
 These are not showblockers, but missing them is ugly!

I agree. Those have both been discussed several times. One common implication of not having l-value returns is: struct point { int x,y; } ... MyArray!(point) arr; ... arr[5].x = 3; // no effect
 The explicit L-value return however I think is an important
 concept that is missing with subtle implications. Without it,
 user defined types can never be made transparent to 
 builtin types. Consider:
 
 int a;
 (+a) = 3;
 
 The unary plus operator returns an L-value, so the assignment
 can take place. In C++, you can define the unary + operator
 to behave the same for your type, by defining both R-value
 and L-value operator:
 
 // R-value unary +
 const mytype &operator +( const mytype &object )
 { return object; }
 
 // L-value unary +
 mytype &operator +( mytype &object )
 { return object; }
 
 In D, you can only do the R-value version.

Yes. This is the area where I find D most lacking. /Oskar
Jun 13 2006
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Oskar Linde wrote:
 cschueler skrev:
 There is more missing in D that prevents me to port the
 system fully:

 - explicit return by reference (return an L-value)
 - struct constructors

 These are not showblockers, but missing them is ugly!

I agree. Those have both been discussed several times. One common implication of not having l-value returns is: struct point { int x,y; } .... MyArray!(point) arr; .... arr[5].x = 3; // no effect

Write MyArray.opIndex to return a pointer and it will work. I do still agree with the proposal, however. -- Chris Nicholson-Sauls
Jun 13 2006
parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Chris Nicholson-Sauls skrev:
 Oskar Linde wrote:
 cschueler skrev:
 There is more missing in D that prevents me to port the
 system fully:

 - explicit return by reference (return an L-value)
 - struct constructors

 These are not showblockers, but missing them is ugly!

I agree. Those have both been discussed several times. One common implication of not having l-value returns is: struct point { int x,y; } .... MyArray!(point) arr; .... arr[5].x = 3; // no effect

Write MyArray.opIndex to return a pointer and it will work. I do still agree with the proposal, however.

That will work in this case, but will break the rvalue case instead: point pt = arr[6]; /Oskar
Jun 13 2006
parent "Regan Heath" <regan netwin.co.nz> writes:
On Tue, 13 Jun 2006 18:56:23 +0200, Oskar Linde  
<oskar.lindeREM OVEgmail.com> wrote:
 Chris Nicholson-Sauls skrev:
 Oskar Linde wrote:
 cschueler skrev:
 There is more missing in D that prevents me to port the
 system fully:

 - explicit return by reference (return an L-value)
 - struct constructors

 These are not showblockers, but missing them is ugly!

I agree. Those have both been discussed several times. One common implication of not having l-value returns is: struct point { int x,y; } .... MyArray!(point) arr; .... arr[5].x = 3; // no effect

still agree with the proposal, however.

That will work in this case, but will break the rvalue case instead: point pt = arr[6];

point pt = *arr[6]; should work. Regan
Jun 13 2006