www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why can't I inherit (extend) structs?

reply Lionello Lunesu <lio lunesu.remove.com> writes:
I like the definition of 'struct' in D: simple aggregations of data. But 
is there currently a way to extend a struct? Apart from composition, 
that is. I'd like to do something like this:

struct X {
   int x;
}
	
struct Z : X {
   int z;
}

Would this feature add complications that I fail to see?

It's not a big deal, since I can use composition, but I'll have to name 
a member for the first struct and repeatedly write it.. And I'm lazy :S

L.
Oct 10 2006
next sibling parent reply Mike Parker <aldacron71 yahoo.com> writes:
Lionello Lunesu wrote:
 I like the definition of 'struct' in D: simple aggregations of data. But 
 is there currently a way to extend a struct? Apart from composition, 
 that is. I'd like to do something like this:
 
 struct X {
   int x;
 }
     
 struct Z : X {
   int z;
 }
 
 Would this feature add complications that I fail to see?
 
 It's not a big deal, since I can use composition, but I'll have to name 
 a member for the first struct and repeatedly write it.. And I'm lazy :S
 
Once you start extending structs, you'll need the same bookkeeping overhead required for classes. That eliminates the current distinction between them.
Oct 10 2006
parent "Lionello Lunesu" <lionello lunesu.remove.com> writes:
"Mike Parker" <aldacron71 yahoo.com> wrote in message 
news:eggji8$1kih$1 digitaldaemon.com...
 Lionello Lunesu wrote:
 I like the definition of 'struct' in D: simple aggregations of data. But 
 is there currently a way to extend a struct? Apart from composition, that 
 is. I'd like to do something like this:

 struct X {
   int x;
 }
     struct Z : X {
   int z;
 }

 Would this feature add complications that I fail to see?

 It's not a big deal, since I can use composition, but I'll have to name a 
 member for the first struct and repeatedly write it.. And I'm lazy :S
Once you start extending structs, you'll need the same bookkeeping overhead required for classes. That eliminates the current distinction between them.
I don't need polymorphism and all that, just to add fields to an existing struct, like Derek's example: struct ColorRGB and then a struct ColorRGBA, which adds a field for the alpha (=transparency). Seems I can use mixins for this, at the moment. But there's shouldn't be extra bookkeeping. It should be like composition; like adding a nameless instance of the 'base' struct as the first member in the derived struct. L.
Oct 10 2006
prev sibling parent reply rm <roel.mathys gmail.com> writes:
Lionello Lunesu wrote:
 It's not a big deal, since I can use composition
but mixin' it in, works nicely rm ========================================= private import std.stdio; template XT() { struct { int x; } } struct X { mixin XT; } struct Z { mixin XT; int z; } void main() { X x; x.x = 5; writefln(x.x); Z z; z.x = 1; z.z = 2; writefln(z.x,' ',z.z); }
Oct 10 2006
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"rm" <roel.mathys gmail.com> wrote in message 
news:egh0bu$2155$1 digitaldaemon.com...
 Lionello Lunesu wrote:
 It's not a big deal, since I can use composition
but mixin' it in, works nicely
Then you have to make sure to mix in the correct base structs in the correct order, and you still don't get type polymorphism (i.e. you can't have a pointer to a Base struct point to a Derived struct; you have to write Base* b = cast(Base*)derived;). Not to mention the sheer pain in the behind of managing a struct and its matching "members" template. It seems far more intuitive to be able to write ------- struct Base { int x; } struct Derived : Base { int y; } ------- Than ------- template BaseMembers() { int x; } struct Base { mixin BaseMembers; } template DerivedMembers() { int y; } struct Derived { mixin BaseMembers; mixin DerivedMembers; } ------- Technically in this example you don't need to have DerivedMembers, but if you wanted to derive from Derived, you'd have to.
Oct 10 2006
next sibling parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Tue, 10 Oct 2006 23:26:01 -0400, Jarrett Billingsley wrote:

 "rm" <roel.mathys gmail.com> wrote in message 
 news:egh0bu$2155$1 digitaldaemon.com...
 Lionello Lunesu wrote:
 It's not a big deal, since I can use composition
but mixin' it in, works nicely
I know I'm just dreaming but it would be very nice-to-have if one could do this ... struct Color { ubyte Red; ubyte Green; ubyte Blue; } struct Pixel extends Color { ubyte Alpha; } Pixel Z Z.Red = 80; Z.Blue = 125; Z.Green = 0; Z.Alpha = 128; rather than struct Color { ubyte Red; ubyte Green; ubyte Blue; } struct Pixel { Color color; ubyte Alpha; } Pixel Z Z.color.Red = 80; Z.color.Blue = 125; Z.color.Green = 0; Z.Alpha = 128; -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 11/10/2006 2:18:29 PM
Oct 10 2006
next sibling parent "Lionello Lunesu" <lionello lunesu.remove.com> writes:
"Derek Parnell" <derek nomail.afraid.org> wrote in message 
news:ck4ro83hyjuv.1npxvrwohfkgk.dlg 40tude.net...
 On Tue, 10 Oct 2006 23:26:01 -0400, Jarrett Billingsley wrote:

 "rm" <roel.mathys gmail.com> wrote in message
 news:egh0bu$2155$1 digitaldaemon.com...
 Lionello Lunesu wrote:
 It's not a big deal, since I can use composition
but mixin' it in, works nicely
I know I'm just dreaming but it would be very nice-to-have if one could do this ...
<snip> That's exactly what I want to be able to do, too! L.
Oct 10 2006
prev sibling parent reply Georg Wrede <georg.wrede nospam.org> writes:
Derek Parnell wrote:
 On Tue, 10 Oct 2006 23:26:01 -0400, Jarrett Billingsley wrote:
 
 
"rm" <roel.mathys gmail.com> wrote in message 
news:egh0bu$2155$1 digitaldaemon.com...

Lionello Lunesu wrote:

It's not a big deal, since I can use composition
but mixin' it in, works nicely
I know I'm just dreaming but it would be very nice-to-have if one could do this ... struct Color { ubyte Red; ubyte Green; ubyte Blue; } struct Pixel extends Color { ubyte Alpha; } Pixel Z Z.Red = 80; Z.Blue = 125; Z.Green = 0; Z.Alpha = 128; rather than struct Color { ubyte Red; ubyte Green; ubyte Blue; } struct Pixel { Color color; ubyte Alpha; } Pixel Z Z.color.Red = 80; Z.color.Blue = 125; Z.color.Green = 0; Z.Alpha = 128;
This could of course be implemented in D. And I think it would be useful. struct A { somefield a; } struct B: A { otherfield b; } And the compiler would simply slap the A fields at the beginning of B. Off-hand I don't see why this would be difficult to implement. But implementing this would cause demands for multiple inheritance. struct A { alpha a; } struct B { beta b; } struct C: A B { gamma c; } And all's well, except when folks start doing struct D: B A { } struct E: C D { } Then what? Of course we could have a restriction that says all of the inherited fields must have unique names. This, admittedly arbitrary restriction could make usage and code clearer, and expunge ambiguities. struct Frozen_Pizza: Comestible Consumable Perishable { } At this point one might start wondering whether the pros outweigh the cost. (And the possible cons?) I don't have an opinion on this yet. But doing struct Frozen_Pizza { Comestible Consumable Perishable } might not be all too labourious in a real-world situation, after all? Except when we want to use polymorphism. Frozen_Pizza fp = new Frozen_Pizza; Perishable p = fp; // insert the use-before dates in p Implementing this without any tables would be nice. Just plain structs, and the compiler would simply create and manipulate the derived structs "as usual".
Oct 14 2006
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Georg Wrede wrote:
 
 This could of course be implemented in D. And I think it would be useful.
 
 struct A
 {
     somefield a;
 }
 
 struct B: A
 {
     otherfield b;
 }
 
 And the compiler would simply slap the A fields at the beginning of B. 
 Off-hand I don't see why this would be difficult to implement. But 
 implementing this would cause demands for multiple inheritance.
 
 struct A
 {
     alpha a;
 }
 struct B
 {
     beta b;
 }
 struct C: A B
 {
     gamma c;
 }
 
 And all's well, except when folks start doing
 
 struct D: B A
 {
 }
 struct E: C D
 {
 }
 
The response to "demands for multiple inheritance" should simply be "No". D doesn't support multiple inheritance for classes even, so it seems odd that it would go out of its way to allow it for structs. I see nothing wrong with just saying structs can only do single inheritance. --bb
Oct 15 2006
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Mon, 16 Oct 2006 09:20:42 +0900, Bill Baxter wrote:

 The response to "demands for multiple inheritance" should simply be "No".
 
 D doesn't support multiple inheritance for classes even, so it seems odd 
 that it would go out of its way to allow it for structs.  I see nothing 
 wrong with just saying structs can only do single inheritance.
And I'd go so far as to say that the term 'inheritance' is a bit strong. Maybe just 'derivation' as we would be deriving a new struct definition from existing definitions, but there is no implied linkage between them at runtime. But this would have to be a 2.0 feature anyway as it is not a *required* language feature. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 16/10/2006 11:38:37 AM
Oct 15 2006
parent reply Johan Granberg <lijat.meREM OVEgmail.com> writes:
Derek Parnell wrote:
 And I'd go so far as to say that the term 'inheritance' is a bit strong.
 Maybe just 'derivation' as we would be deriving a new struct definition
 from existing definitions, but there is no implied linkage between them at
 runtime. 
If it is just derived from that is wanted wouldn't it bee easier with a syntax like this. struct foo { int b; int c; } struct bar { int a include foo; int d } the struct bar would now have four fields (a,b,c,d) this way their is no way to misunderstand it for inheritance and if one want a foo* one can always take the addres of the first element.
Oct 16 2006
next sibling parent reply Derek Parnell <derek psyc.ward> writes:
On Mon, 16 Oct 2006 18:49:20 +0200, Johan Granberg wrote:

 Derek Parnell wrote:
 And I'd go so far as to say that the term 'inheritance' is a bit strong.
 Maybe just 'derivation' as we would be deriving a new struct definition
 from existing definitions, but there is no implied linkage between them at
 runtime. 
If it is just derived from that is wanted wouldn't it bee easier with a syntax like this. struct foo { int b; int c; } struct bar { int a include foo; int d } the struct bar would now have four fields (a,b,c,d) this way their is no way to misunderstand it for inheritance and if one want a foo* one can always take the addres of the first element.
Hey ... not bad. -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Oct 16 2006
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Derek Parnell wrote:
 On Mon, 16 Oct 2006 18:49:20 +0200, Johan Granberg wrote:
 
 Derek Parnell wrote:
 And I'd go so far as to say that the term 'inheritance' is a bit strong.
 Maybe just 'derivation' as we would be deriving a new struct definition
 from existing definitions, but there is no implied linkage between them at
 runtime. 
If it is just derived from that is wanted wouldn't it bee easier with a syntax like this. struct foo { int b; int c; } struct bar { int a include foo; int d } the struct bar would now have four fields (a,b,c,d) this way their is no way to misunderstand it for inheritance and if one want a foo* one can always take the addres of the first element.
Hey ... not bad.
By "first element" you mean "first foo element in bar"? Isn't that just a mixin without the namespace? Anyway, I thought the point of this was so that you could pass a bar* to a function that takes a foo*. If foo is jammed in somewhere in the middle of bar then that's not so straightforward. I guess the compiler could automatically offset the bar* to its foo part if it sees the bar* is being used in a foo* context. But that seems kinda tricky to get right. --bb
Oct 16 2006
parent Johan Granberg <lijat.meREM OVEgmail.com> writes:
Bill Baxter wrote:
 Derek Parnell wrote:
 On Mon, 16 Oct 2006 18:49:20 +0200, Johan Granberg wrote:

 Derek Parnell wrote:
 And I'd go so far as to say that the term 'inheritance' is a bit 
 strong.
 Maybe just 'derivation' as we would be deriving a new struct definition
 from existing definitions, but there is no implied linkage between 
 them at
 runtime. 
If it is just derived from that is wanted wouldn't it bee easier with a syntax like this. struct foo { int b; int c; } struct bar { int a include foo; int d } the struct bar would now have four fields (a,b,c,d) this way their is no way to misunderstand it for inheritance and if one want a foo* one can always take the addres of the first element.
Hey ... not bad.
By "first element" you mean "first foo element in bar"? Isn't that just a mixin without the namespace? Anyway, I thought the point of this was so that you could pass a bar* to a function that takes a foo*. If foo is jammed in somewhere in the middle of bar then that's not so straightforward. I guess the compiler could automatically offset the bar* to its foo part if it sees the bar* is being used in a foo* context. But that seems kinda tricky to get right. --bb
I you put foo first in bar that would work otherwise you would have to offset the address yourself. Yes it is much like a mixin the difference is that you are mixing in a struct instead of a template.
Oct 16 2006
prev sibling parent Lionello Lunesu <lio lunesu.remove.com> writes:
Johan Granberg wrote:
 Derek Parnell wrote:
 And I'd go so far as to say that the term 'inheritance' is a bit strong.
 Maybe just 'derivation' as we would be deriving a new struct definition
 from existing definitions, but there is no implied linkage between 
 them at
 runtime. 
If it is just derived from that is wanted wouldn't it bee easier with a syntax like this. struct foo { int b; int c; } struct bar { int a include foo; int d } the struct bar would now have four fields (a,b,c,d) this way their is no way to misunderstand it for inheritance and if one want a foo* one can always take the addres of the first element.
Good! Perhaps the keyword "mixin" could be (mis)used for this? L.
Oct 16 2006
prev sibling parent reply rm <roel.mathys gmail.com> writes:
Jarrett Billingsley wrote:
 
 Then you have to make sure to mix in the correct base structs in the correct 
 order
why do you say correct order? when mixin in 2 structs with the same-named member, the first time I reference that member in the new struct, the thing won't compile any more? rm ========================================================= private import std.stdio; template XT() { struct { int x; } } template YT() { struct { int x; } } struct X { mixin XT; } struct Z { mixin XT; mixin YT; int z; } void main() { X x; x.x = 5; writefln(x.x); Z z; z.x = 1; z.z = 2; writefln(z.x,' ',z.z); }
Oct 11 2006
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"rm" <roel.mathys gmail.com> wrote in message 
news:egj6fb$1ih4$1 digitaldaemon.com...

 why do you say correct order?
It matters when you're dealing with system libraries that expect structures to be laid out in a certain way, and it matters if you want to have type polymorphism (i.e. casting a pointer to a derived structure to a base structure type). I.e. template BaseMembers() { int x; } template DerivedMembers() { int y; } struct Base { mixin BaseMembers; } struct Derived { mixin DerivedMembers; // oops! wrong order mixin BaseMembers; } void main() { Derived d; d.x = 3; d.y = 4; Base* b = cast(Base*)&d; writefln(b.x); // prints "4", not "3" } The compiler can't complain about something like this because it doesn't know anything about deriving structs and keeping their members in the correct order in memory. With the ability to derive structs, the problem just goes away.
Oct 11 2006
prev sibling parent "Lionello Lunesu" <lionello lunesu.remove.com> writes:
"rm" <roel.mathys gmail.com> wrote in message 
news:egh0bu$2155$1 digitaldaemon.com...
 Lionello Lunesu wrote:
 It's not a big deal, since I can use composition
but mixin' it in, works nicely
<snip> Good idea.. I'll try that.. L.
Oct 10 2006