www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - struct mixins

reply Leandro Lucarella <llucax gmail.com> writes:
struct inheritance never make it into D, for a good reason: structs are
not supposed to be polymorphic and inheritance is very tied to
polymorphism. But struct inheritance is sometimes very useful for
"composition", avoid an extra member when accessing to the composed type
members.

Example:

struct A {
	int x;
	int y;
}

struct B {
	A a;
	int z;
}

B b;
b.a.x = 5;

A way to "fix" this is using template mixins:

template Common() {
	int x;
	int y;
}

struct A {
	mixin Common;
}

struct B {
	mixin Common;
	int z;
}

B b;
b.x = 5;

But one can think this is even worse than the previous approach :)

What if one could use a struct directly with mixin?

struct A {
	int x;
	int y;
}

struct B {
	mixin A;
	int z;
}

B b;
b.x = 5;


I think this is nice, looks good, is backwards compatible, it might be
easy to implement (not sure about that though) and can be even extended to
classes (not sure about the usefulness of that either).

The only problem are name collisions, but that can already happen with
template mixins, right? Anyway, collisions can yield a compile error, or
they might be accepted, requiring the full qualified name to access the
attribute, like with classes and inheritance (you can't do a mixin of the
same struct twice). Say A is updated in the future:

struct A {
	int x;
	int y;
	int z;
}

b.z = 1; // changes B.z
// to modify B.A.z:
b.A.z = 1;


I think collisions should be very rare anyways in structs.

PS: For those who wonder, yes, this is inspired in the "embedding" feature
    of Google's Go, which is basically a mixin, but without adding
    template to the mix, it's just this, struct mixins.


-- 
Leandro Lucarella (AKA luca)                     http://llucax.com.ar/
----------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------
El techo de mi cuarto lleno de universos
Nov 16 2009
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 16 Nov 2009 10:32:31 -0500, Leandro Lucarella <llucax gmail.com>  
wrote:

 What if one could use a struct directly with mixin?
This is a very good idea. BTW, I think conflicts should be a compile-time error. -Steve
Nov 16 2009
parent Leandro Lucarella <llucax gmail.com> writes:
Steven Schveighoffer, el 16 de noviembre a las 10:44 me escribiste:
 On Mon, 16 Nov 2009 10:32:31 -0500, Leandro Lucarella
 <llucax gmail.com> wrote:
 
What if one could use a struct directly with mixin?
This is a very good idea. BTW, I think conflicts should be a compile-time error.
I think compile-time error is nice and clean, but you are lost if you're using a third-party struct, and the maintainer adds a new field that collides with yours. Example: struct ThirdParty { int x; } struct Mine { mixin ThirdParty; int y; } void myCode(Mine m) { m.y = 1; } If ThirdParty is changed like this: struct ThirdParty { int x; int y; } Then your code don't compile anymore and you can't fix it. Either you stop using mixin ThirdParty or you have to change your struct and *all* the code written for it. On the other hand, if you allow explicit disambiguation, you code still compiles and work as expected. You just won't use the new y variable from ThirdParty (you didn't use it before either, so that's OK). If you need to start using the new y attribute from ThirdParty, you can do it with: void myCode(Mine m) { m.y = m.ThirdParty.y; } -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Yeah, I'm a great quitter. It's one of the few things I do well. I come from a long line of quitters. My father was a quitter, my grandfather was a quitter... I was raised to give up. -- George Constanza
Nov 16 2009
prev sibling next sibling parent reply Frank Benoit <keinfarbton googlemail.com> writes:
Reminds me of an older thread:
http://www.digitalmars.com/d/archives/digitalmars/D/Implicit_castable_structs_64764.html
Nov 16 2009
next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 16 Nov 2009 18:58:42 +0300, Frank Benoit  
<keinfarbton googlemail.com> wrote:

 Reminds me of an older thread:
 http://www.digitalmars.com/d/archives/digitalmars/D/Implicit_castable_structs_64764.html
I recall it, but I still think "alias this" is the way to go: struct GtkWidget{ /* data member */ } struct GtkContainer{ GtkWidget widget; // mixin GtkWidget; could also work, though // more data members alias this &widget; // how would you do the same without a named mixin? // And what's the benefit of named mixin over plain old aggregation? }
Nov 16 2009
parent Leandro Lucarella <llucax gmail.com> writes:
Denis Koroskin, el 16 de noviembre a las 19:03 me escribiste:
 On Mon, 16 Nov 2009 18:58:42 +0300, Frank Benoit
 <keinfarbton googlemail.com> wrote:
 
Reminds me of an older thread:
http://www.digitalmars.com/d/archives/digitalmars/D/Implicit_castable_structs_64764.html
I recall it, but I still think "alias this" is the way to go: struct GtkWidget{ /* data member */ } struct GtkContainer{ GtkWidget widget; // mixin GtkWidget; could also work, though // more data members alias this &widget; // how would you do the same without a named mixin? // And what's the benefit of named mixin over plain old aggregation? }
See how a struct mixin could add an implicit/explicit cast to the mixed in structs. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Con vos hay pica, patovica! -- Sidharta Kiwi
Nov 16 2009
prev sibling parent Leandro Lucarella <llucax gmail.com> writes:
Frank Benoit, el 16 de noviembre a las 16:58 me escribiste:
 Reminds me of an older thread:
 http://www.digitalmars.com/d/archives/digitalmars/D/Implicit_castable_structs_64764.html
I think mixin can mix very well with that proposal, when the compiler sees a struct mixin, it can automatically provide an {im,ex}plicit cast to the mixed in type, adjusting the pointer: struct A { int x; } struct B { int y; } struct C { mixin A; mixin B; } C* c = new C; A* a = cast(A*) c; // points to c B* a = cast(B*) c; // points to c + A.sizeof -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Cómo ser inconmensurablemente atractivo a la mujer del sexo opuesto. -- Libro de autoayuda de Hector Mesina.
Nov 16 2009
prev sibling parent reply div0 <div0 users.sourceforge.net> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Leandro Lucarella wrote:
 struct inheritance never make it into D, for a good reason: structs are
 not supposed to be polymorphic and inheritance is very tied to
 polymorphism. But struct inheritance is sometimes very useful for
 "composition", avoid an extra member when accessing to the composed type
 members.
 
 Example:
 
 struct A {
 	int x;
 	int y;
 }
 
 struct B {
 	A a;
 	int z;
 }
 
 B b;
 b.a.x = 5;
 
 A way to "fix" this is using template mixins:
 
 template Common() {
 	int x;
 	int y;
 }
 
 struct A {
 	mixin Common;
 }
 
 struct B {
 	mixin Common;
 	int z;
 }
 
 B b;
 b.x = 5;
 
 But one can think this is even worse than the previous approach :)
 
 What if one could use a struct directly with mixin?
 
 struct A {
 	int x;
 	int y;
 }
 
 struct B {
 	mixin A;
 	int z;
 }
 
 B b;
 b.x = 5;
 
 
 I think this is nice, looks good, is backwards compatible, it might be
 easy to implement (not sure about that though) and can be even extended to
 classes (not sure about the usefulness of that either).
 
 The only problem are name collisions, but that can already happen with
 template mixins, right? Anyway, collisions can yield a compile error, or
 they might be accepted, requiring the full qualified name to access the
 attribute, like with classes and inheritance (you can't do a mixin of the
 same struct twice). Say A is updated in the future:
 
 struct A {
 	int x;
 	int y;
 	int z;
 }
 
 b.z = 1; // changes B.z
 // to modify B.A.z:
 b.A.z = 1;
 
 
 I think collisions should be very rare anyways in structs.
 
 PS: For those who wonder, yes, this is inspired in the "embedding" feature
     of Google's Go, which is basically a mixin, but without adding
     template to the mix, it's just this, struct mixins.
 
 
vote++ I was going to suggest it when I finished my spirit port, but I was too lazy to in the end. It would be very handy as currently the only way support multiple policies is to use member vars which are basically pointers to empty classes, so it looks rather more ugly than it needs to be. Mixin should really go hog wild I think and let you mixin anything anywhere. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iD8DBQFLAajpT9LetA9XoXwRAkDsAKCZ59OTxLlqoKUZFVMkElBOED/ihwCfbBf9 txVFtwPyKxkrYmYHzVeETI4= =o8VR -----END PGP SIGNATURE-----
Nov 16 2009
parent reply Bill Baxter <wbaxter gmail.com> writes:
On Mon, Nov 16, 2009 at 11:32 AM, div0 <div0 users.sourceforge.net> wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Leandro Lucarella wrote:
 struct inheritance never make it into D, for a good reason: structs are
 not supposed to be polymorphic and inheritance is very tied to
 polymorphism. But struct inheritance is sometimes very useful for
 "composition", avoid an extra member when accessing to the composed type
 members.

 Example:

 struct A {
 =A0 =A0 =A0 int x;
 =A0 =A0 =A0 int y;
 }

 struct B {
 =A0 =A0 =A0 A a;
 =A0 =A0 =A0 int z;
 }

 B b;
 b.a.x =3D 5;

 A way to "fix" this is using template mixins:

 template Common() {
 =A0 =A0 =A0 int x;
 =A0 =A0 =A0 int y;
 }

 struct A {
 =A0 =A0 =A0 mixin Common;
 }

 struct B {
 =A0 =A0 =A0 mixin Common;
 =A0 =A0 =A0 int z;
 }

 B b;
 b.x =3D 5;

 But one can think this is even worse than the previous approach :)

 What if one could use a struct directly with mixin?

 struct A {
 =A0 =A0 =A0 int x;
 =A0 =A0 =A0 int y;
 }

 struct B {
 =A0 =A0 =A0 mixin A;
 =A0 =A0 =A0 int z;
 }

 B b;
 b.x =3D 5;


 I think this is nice, looks good, is backwards compatible, it might be
 easy to implement (not sure about that though) and can be even extended =
to
 classes (not sure about the usefulness of that either).

 The only problem are name collisions, but that can already happen with
 template mixins, right? Anyway, collisions can yield a compile error, or
 they might be accepted, requiring the full qualified name to access the
 attribute, like with classes and inheritance (you can't do a mixin of th=
e
 same struct twice). Say A is updated in the future:

 struct A {
 =A0 =A0 =A0 int x;
 =A0 =A0 =A0 int y;
 =A0 =A0 =A0 int z;
 }

 b.z =3D 1; // changes B.z
 // to modify B.A.z:
 b.A.z =3D 1;


 I think collisions should be very rare anyways in structs.

 PS: For those who wonder, yes, this is inspired in the "embedding" featu=
re
 =A0 =A0 of Google's Go, which is basically a mixin, but without adding
 =A0 =A0 template to the mix, it's just this, struct mixins.
vote++ I was going to suggest it when I finished my spirit port, but I was too lazy to in the end. It would be very handy as currently the only way support multiple policies is to use member vars which are basically pointers to empty classes, so it looks rather more ugly than it needs to be. Mixin should really go hog wild I think and let you mixin anything anywhe=
re. I have wanted this kind of thing before too. I can't recall the exact reason, but it had something to do with traits structs. I hit it when I was porting OpenMesh to D. There's some base set of traits provided by the library as a struct that you may want to add too in user code. But I think "alias this" would probably serve that need just fine. What use cases are served by the mixin that 'alias this' does not? It looks like this was an attempt to explain, but I don't understand: "See how a struct mixin could add an implicit/explicit cast to the mixed in structs." I guess mixin struct could allow a kind of static multiple inheritance. But if that's desirable, then probably alias this should just be extended to enable that. Seems like the two are so similar that whatever alias this lacks in features could just be added rather than introducing a new construct. --bb
Nov 16 2009
next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Bill Baxter, el 16 de noviembre a las 13:08 me escribiste:
 On Mon, Nov 16, 2009 at 11:32 AM, div0 <div0 users.sourceforge.net> wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Leandro Lucarella wrote:
 struct inheritance never make it into D, for a good reason: structs are
 not supposed to be polymorphic and inheritance is very tied to
 polymorphism. But struct inheritance is sometimes very useful for
 "composition", avoid an extra member when accessing to the composed type
 members.

 Example:

 struct A {
       int x;
       int y;
 }

 struct B {
       A a;
       int z;
 }

 B b;
 b.a.x = 5;

 A way to "fix" this is using template mixins:

 template Common() {
       int x;
       int y;
 }

 struct A {
       mixin Common;
 }

 struct B {
       mixin Common;
       int z;
 }

 B b;
 b.x = 5;

 But one can think this is even worse than the previous approach :)

 What if one could use a struct directly with mixin?

 struct A {
       int x;
       int y;
 }

 struct B {
       mixin A;
       int z;
 }

 B b;
 b.x = 5;


 I think this is nice, looks good, is backwards compatible, it might be
 easy to implement (not sure about that though) and can be even extended to
 classes (not sure about the usefulness of that either).

 The only problem are name collisions, but that can already happen with
 template mixins, right? Anyway, collisions can yield a compile error, or
 they might be accepted, requiring the full qualified name to access the
 attribute, like with classes and inheritance (you can't do a mixin of the
 same struct twice). Say A is updated in the future:

 struct A {
       int x;
       int y;
       int z;
 }

 b.z = 1; // changes B.z
 // to modify B.A.z:
 b.A.z = 1;


 I think collisions should be very rare anyways in structs.

 PS: For those who wonder, yes, this is inspired in the "embedding" feature
     of Google's Go, which is basically a mixin, but without adding
     template to the mix, it's just this, struct mixins.
vote++ I was going to suggest it when I finished my spirit port, but I was too lazy to in the end. It would be very handy as currently the only way support multiple policies is to use member vars which are basically pointers to empty classes, so it looks rather more ugly than it needs to be. Mixin should really go hog wild I think and let you mixin anything anywhere.
I have wanted this kind of thing before too. I can't recall the exact reason, but it had something to do with traits structs. I hit it when I was porting OpenMesh to D. There's some base set of traits provided by the library as a struct that you may want to add too in user code. But I think "alias this" would probably serve that need just fine. What use cases are served by the mixin that 'alias this' does not? It looks like this was an attempt to explain, but I don't understand: "See how a struct mixin could add an implicit/explicit cast to the mixed in structs."
I meant to say: "See how a struct mixin could add an implicit/explicit cast to the mixed in structs in my previous mail." Which would be: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=101242 Maybe I don't fully understand alias this. Does alias this can do that?
 I guess mixin struct could allow a kind of static multiple
 inheritance.  But if that's desirable, then probably alias this should
 just be extended to enable that.  Seems like the two are so similar
 that whatever alias this lacks in features could just be added rather
 than introducing a new construct.
I really didn't thought about alias this when making this proposal (I had this problem using D1, I'm not using D2 much), so maybe you are right. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- EL "PITUFO ENRIQUE" LLEGO A LA BAILANTA -- Crónica TV
Nov 16 2009
prev sibling parent reply div0 <div0 users.sourceforge.net> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Bill Baxter wrote:
 On Mon, Nov 16, 2009 at 11:32 AM, div0 <div0 users.sourceforge.net> wrote:
<snip>

 vote++

 I was going to suggest it when I finished my spirit port, but I was
 too lazy to in the end.

 It would be very handy as currently the only way support multiple
 policies is to use member vars which are basically pointers to empty
 classes, so it looks rather more ugly than it needs to be.

 Mixin should really go hog wild I think and let you mixin anything anywhere.
I have wanted this kind of thing before too. I can't recall the exact reason, but it had something to do with traits structs. I hit it when I was porting OpenMesh to D. There's some base set of traits provided by the library as a struct that you may want to add too in user code. But I think "alias this" would probably serve that need just fine. What use cases are served by the mixin that 'alias this' does not? It looks like this was an attempt to explain, but I don't understand: "See how a struct mixin could add an implicit/explicit cast to the mixed in structs." I guess mixin struct could allow a kind of static multiple inheritance. But if that's desirable, then probably alias this should just be extended to enable that. Seems like the two are so similar that whatever alias this lacks in features could just be added rather than introducing a new construct. --bb
Well at the moment you only get one alias this. I suppose you could allow multiple alias this, but then what happens with multiple symbols with the same name? At least with mixins you can disambiguate. Still using member vars worked for me; there's more important stuff to be doing at the moment. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iD8DBQFLAvMpT9LetA9XoXwRAuIZAKCyRCfzrXGEPJeH7n1zC/UcrHvsKACdFX8F qp4lpEqHtf0ruF0XSHVQUXM= =2zvO -----END PGP SIGNATURE-----
Nov 17 2009
parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Nov 17, 2009 at 11:02 AM, div0 <div0 users.sourceforge.net> wrote:

 I guess mixin struct could allow a kind of static multiple
 inheritance. =A0But if that's desirable, then probably alias this should
 just be extended to enable that. =A0Seems like the two are so similar
 that whatever alias this lacks in features could just be added rather
 than introducing a new construct.

 --bb
Well at the moment you only get one alias this. I suppose you could allow multiple alias this, but then what happens with multiple symbols with the same name? At least with mixins you can disambiguate.
I don't see why you couldn't allow alias this to give you the same disambiguation capability. Or just get rid of alias this in favor of type mixins. Doesn't really matter to me. But I'm not seeing any reason to have both constructs when they do almost the same thing. --bb
Nov 17 2009