Thread overview
struct inheritance, L-value return
Jun 13, 2006
cschueler
Jun 13, 2006
mclysenk
Jun 13, 2006
Oskar Linde
Jun 13, 2006
Oskar Linde
Jun 13, 2006
Regan Heath
June 13, 2006
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.



June 13, 2006
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


June 13, 2006
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
June 13, 2006
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
June 13, 2006
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
June 13, 2006
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
>>>
>>  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];

point pt = *arr[6];

should work.

Regan