www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - struct inheritance

reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
verily it doth say:

     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }

Why not just allow mixin to do this?

     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }

That's basically the way it's done now except now it would be more like:
template MMixin() { int a; }
struct M { mixin M; }
struct S { mixin M; int b; }

Just let us treat a struct like a zero arg template for mixin purposes.

--bb
Aug 30 2007
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:
 
      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }
 
 Why not just allow mixin to do this?
 
      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }
 
 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }
 
 Just let us treat a struct like a zero arg template for mixin purposes.
 
 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".
Aug 30 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Robert Fraser wrote:
 Bill Baxter Wrote:
 
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb
Aug 30 2007
parent reply kris <foo bar.com> writes:
Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M. Hence, it would seem the right way to do this is to take it out of the hands of the developer and do something akin to # struct S : M as had been suggested previously. Sure, that particular syntax may mean something else to some C++ folks, but at least the intent is clear and the /outcome/ is consistent. BTW, did you select S&M for a specific reason? :p
Aug 30 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
kris wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M.

Well for the 'import' syntax it wouldn't be so bad. The compiler could just say "imported members will always appear first". With the alias syntax that would be a bit weirder since there's already an "M m" right there in the struct (which I assume you would still be able to access via the .m). Since there's a visible member there, it makes less sense for the compiler to move the fields around.
 Hence, it would seem the right way 
 to do this is to take it out of the hands of the developer and do 
 something akin to
 
 #    struct S : M
 
 as had been suggested previously. Sure, that particular syntax may mean 
 something else to some C++ folks, but at least the intent is clear and 
 the /outcome/ is consistent.

Yeh. I agree. I think that syntax would be better too. I was just assuming that *not* using that syntax was something that we wouldn't change Walter's mind about. But maybe there's hope.
 BTW, did you select S&M for a specific reason? :p

You'll have to ask Walter about that :-) It's right from their presentation. --bb
Aug 30 2007
parent Reiner Pope <some address.com> writes:
Bill Baxter wrote:
 kris wrote:
 Perhaps a bigger problem is this:

 #       struct M { int a; }
 #       struct S {
 #          int b;
 #          import M;
 #       }

 Now, S is no longer derived from M. 

Well for the 'import' syntax it wouldn't be so bad. The compiler could just say "imported members will always appear first". With the alias syntax that would be a bit weirder since there's already an "M m" right there in the struct (which I assume you would still be able to access via the .m). Since there's a visible member there, it makes less sense for the compiler to move the fields around.

I'm not sure why imported members do have to appear first. Is there a reason that S is derived from M only if M is the first member of S? In lieu of a vtbl, S being derived from M presumably only means that S can be implicitly converted to M. So what's wrong with writing struct M { int a; } struct S { int b; M m; alias m this; M opImplicitCastTo() { return m; } }
 Hence, it would seem the right way to do this is to take it out of the 
 hands of the developer and do something akin to

 #    struct S : M

 as had been suggested previously. Sure, that particular syntax may 
 mean something else to some C++ folks, but at least the intent is 
 clear and the /outcome/ is consistent.

Yeh. I agree. I think that syntax would be better too. I was just assuming that *not* using that syntax was something that we wouldn't change Walter's mind about. But maybe there's hope.

I think that "alias this" may become more interesting when aliases work with any expression. You could write things like struct S { M m; alias m.a this; } You can't really express this neatly with inheritance (in my opinion). Of course, the import syntax works just as well, but I think alias expresses exactly what you're doing, and doesn't require introduction of a distinct concept to the language. -- Reiner
Aug 30 2007
prev sibling parent reply Regan Heath <regan netmail.co.nz> writes:
kris wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M. Hence, it would seem the right way to do this is to take it out of the hands of the developer and do something akin to # struct S : M as had been suggested previously. Sure, that particular syntax may mean something else to some C++ folks, but at least the intent is clear and the /outcome/ is consistent.

When you say "derived from M" are you referring to the ordering/layout of M matching that of the start of S (new fields of S therefore existing in the part of S which is larger than M). I'm not sure "derived" is the right term to use, we don't want to confuse it with class derivation, perhaps saying "S is based on M" is better? /You say potatoes I say ../ As one of the main reasons/uses for structs is to define a specific layout in memory, perhaps the main reason for Walters syntax is to make it possible to define that layout however required. I think there are cases where they should match, and you should be able to cast from S to M (albeit with slicing and woe to the developer who tries to cast an array of S to M - but perhaps the cast operator can handle this case?). In this case S is based on M. I think there are also cases where you need to specify a different layout and in this case S would not be based on M. Regan
Aug 31 2007
next sibling parent reply kris <foo bar.com> writes:
Regan Heath wrote:
 kris wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin 
 purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M. Hence, it would seem the right way to do this is to take it out of the hands of the developer and do something akin to # struct S : M as had been suggested previously. Sure, that particular syntax may mean something else to some C++ folks, but at least the intent is clear and the /outcome/ is consistent.

When you say "derived from M" are you referring to the ordering/layout of M matching that of the start of S (new fields of S therefore existing in the part of S which is larger than M). I'm not sure "derived" is the right term to use, we don't want to confuse it with class derivation, perhaps saying "S is based on M" is better? /You say potatoes I say ../ As one of the main reasons/uses for structs is to define a specific layout in memory, perhaps the main reason for Walters syntax is to make it possible to define that layout however required. I think there are cases where they should match, and you should be able to cast from S to M (albeit with slicing and woe to the developer who tries to cast an array of S to M - but perhaps the cast operator can handle this case?). In this case S is based on M. I think there are also cases where you need to specify a different layout and in this case S would not be based on M. Regan

Briefy: ok, S /extends/ M :) The ordering becomes an issue when you have a pointer to S, and wish to use it as a pointer to an M. That's why, in C, the super-struct is manually inserted as the first struct member. If you manually insert the super-struct as the second or third member then, obviously, your pointer is not convertible
Aug 31 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
kris wrote:
 Regan Heath wrote:
 kris wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where 
 yea verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin 
 purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M. Hence, it would seem the right way to do this is to take it out of the hands of the developer and do something akin to # struct S : M as had been suggested previously. Sure, that particular syntax may mean something else to some C++ folks, but at least the intent is clear and the /outcome/ is consistent.

When you say "derived from M" are you referring to the ordering/layout of M matching that of the start of S (new fields of S therefore existing in the part of S which is larger than M). I'm not sure "derived" is the right term to use, we don't want to confuse it with class derivation, perhaps saying "S is based on M" is better? /You say potatoes I say ../ As one of the main reasons/uses for structs is to define a specific layout in memory, perhaps the main reason for Walters syntax is to make it possible to define that layout however required. I think there are cases where they should match, and you should be able to cast from S to M (albeit with slicing and woe to the developer who tries to cast an array of S to M - but perhaps the cast operator can handle this case?). In this case S is based on M. I think there are also cases where you need to specify a different layout and in this case S would not be based on M. Regan

Briefy: ok, S /extends/ M :)

<g>
 The ordering becomes an issue when you have a pointer to S, and wish to 
 use it as a pointer to an M. That's why, in C, the super-struct is 
 manually inserted as the first struct member. If you manually insert the 
 super-struct as the second or third member then, obviously, your pointer 
 is not convertible

Yep, exactly. In this case you definately want S to extend M and in this exact manner. However, I wonder if there are cases where you want a different layout in memory. If so, the syntax must support both options. Regan
Aug 31 2007
parent kris <foo bar.com> writes:
Regan Heath wrote:
 kris wrote:

 Briefy:

 ok, S /extends/ M :)

<g>
 The ordering becomes an issue when you have a pointer to S, and wish 
 to use it as a pointer to an M. That's why, in C, the super-struct is 
 manually inserted as the first struct member. If you manually insert 
 the super-struct as the second or third member then, obviously, your 
 pointer is not convertible

Yep, exactly. In this case you definately want S to extend M and in this exact manner. However, I wonder if there are cases where you want a different layout in memory. If so, the syntax must support both options. Regan

If you're not interested in 'extending' per se, but prefer composition, then one will always be able to do this: struct S { int foo, bar; M m; OtherStruct other; char[] wumpus; }
Aug 31 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Regan Heath wrote:
 kris wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin 
 purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M. Hence, it would seem the right way to do this is to take it out of the hands of the developer and do something akin to # struct S : M as had been suggested previously. Sure, that particular syntax may mean something else to some C++ folks, but at least the intent is clear and the /outcome/ is consistent.

When you say "derived from M" are you referring to the ordering/layout of M matching that of the start of S (new fields of S therefore existing in the part of S which is larger than M). I'm not sure "derived" is the right term to use, we don't want to confuse it with class derivation, perhaps saying "S is based on M" is better? /You say potatoes I say ../ As one of the main reasons/uses for structs is to define a specific layout in memory, perhaps the main reason for Walters syntax is to make it possible to define that layout however required.

Another good use for structs is for traits class with little or no data. Mostly just a collection of types and static functions. Having the ability to extend these structs is handy. A library can define a set of base types A, and users can add to or modify it without having to know all the stuff that was in A to begin with. Or vice versa, I define the base and pass that to the library and the library adds a few more things to it. The reason these should be structs is because sometimes you want to add in maybe one or two small data members that control operation. For instance you might have a 'compare' function in the traits and want to parameterize it by a data member to act like either less-than or greater-than. Such things should have value semantics. --bb
Aug 31 2007
next sibling parent reply kris <foo bar.com> writes:
Bill Baxter wrote:
 Regan Heath wrote:
 kris wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where 
 yea verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin 
 purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M. Hence, it would seem the right way to do this is to take it out of the hands of the developer and do something akin to # struct S : M as had been suggested previously. Sure, that particular syntax may mean something else to some C++ folks, but at least the intent is clear and the /outcome/ is consistent.

When you say "derived from M" are you referring to the ordering/layout of M matching that of the start of S (new fields of S therefore existing in the part of S which is larger than M). I'm not sure "derived" is the right term to use, we don't want to confuse it with class derivation, perhaps saying "S is based on M" is better? /You say potatoes I say ../ As one of the main reasons/uses for structs is to define a specific layout in memory, perhaps the main reason for Walters syntax is to make it possible to define that layout however required.

Another good use for structs is for traits class with little or no data. Mostly just a collection of types and static functions. Having the ability to extend these structs is handy. A library can define a set of base types A, and users can add to or modify it without having to know all the stuff that was in A to begin with. Or vice versa, I define the base and pass that to the library and the library adds a few more things to it. The reason these should be structs is because sometimes you want to add in maybe one or two small data members that control operation. For instance you might have a 'compare' function in the traits and want to parameterize it by a data member to act like either less-than or greater-than. Such things should have value semantics. --bb

Another principal use it to enclose an opApply() with some relevant context. Returning such things by value to a foreach() is one of the coolest things about D
Aug 31 2007
parent reply Don Clugston <dac nospam.com.au> writes:
kris wrote:
 Bill Baxter wrote:
 Regan Heath wrote:
 kris wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where 
 yea verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be 
 more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin 
 purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M. Hence, it would seem the right way to do this is to take it out of the hands of the developer and do something akin to # struct S : M as had been suggested previously. Sure, that particular syntax may mean something else to some C++ folks, but at least the intent is clear and the /outcome/ is consistent.

When you say "derived from M" are you referring to the ordering/layout of M matching that of the start of S (new fields of S therefore existing in the part of S which is larger than M). I'm not sure "derived" is the right term to use, we don't want to confuse it with class derivation, perhaps saying "S is based on M" is better? /You say potatoes I say ../ As one of the main reasons/uses for structs is to define a specific layout in memory, perhaps the main reason for Walters syntax is to make it possible to define that layout however required.

Another good use for structs is for traits class with little or no data. Mostly just a collection of types and static functions. Having the ability to extend these structs is handy. A library can define a set of base types A, and users can add to or modify it without having to know all the stuff that was in A to begin with. Or vice versa, I define the base and pass that to the library and the library adds a few more things to it. The reason these should be structs is because sometimes you want to add in maybe one or two small data members that control operation. For instance you might have a 'compare' function in the traits and want to parameterize it by a data member to act like either less-than or greater-than. Such things should have value semantics. --bb

Another principal use it to enclose an opApply() with some relevant context. Returning such things by value to a foreach() is one of the coolest things about D

Looking forward to your next talk "foreach fo' Shizzle". <g>
Sep 03 2007
parent kris <foo bar.com> writes:
Don Clugston wrote:
 kris wrote:

 Another principal use it to enclose an opApply() with some relevant 
 context. Returning such things by value to a foreach() is one of the 
 coolest things about D

Looking forward to your next talk "foreach fo' Shizzle". <g>

heh ... should perhaps try "Yo Mama!" for that one :)
Sep 03 2007
prev sibling parent reply Regan Heath <regan netmail.co.nz> writes:
Bill Baxter wrote:
 Regan Heath wrote:
 kris wrote:
 Bill Baxter wrote:
 Robert Fraser wrote:
 Bill Baxter Wrote:

 Let us all turn our copies of WalterAndrei.pdf to page 40 where 
 yea verily it doth say:

      struct M { int a; }
      struct S {
         M m;
         alias m this;
         int b;
      }

 Why not just allow mixin to do this?

      struct M { int a; }
      struct S {
         mixin M;
         int b;
      }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin 
 purposes.

 --bb

It amounts to the same thing, so it just depends on which syntax you prefer. Personally, I like... struct S : M { int b; } ... meaning S is non-polymorphically inherited from M. I guess the argument against taht syntax was that it would be confusing for people from a C++ background who assume polymorphic inheritance for structs. Anyways, it's up to Walter to decide on the syntax, and he says "alias this".

I did just think of one issue which is that constructors/opCalls for M would be weird. S needs to decide how to initialize the M part, which would be difficult if M's constructors are just mixed in directly. I guess from a compiler-writers perspective "alias this" is more like what actually happens when you inherit in typical C++ fashion. In that case I guess I'd prefer 'import' struct M { int a; } struct S { import M; int b; } then you can specify when you need to access the M parts just like you do in C++ by M.member. I'd even prefer "alias m .;" to "alias m this;". It just seems wrong and goes against the nice happy view that 'this' is just an implicitly defined pointer member. --bb

Perhaps a bigger problem is this: # struct M { int a; } # struct S { # int b; # import M; # } Now, S is no longer derived from M. Hence, it would seem the right way to do this is to take it out of the hands of the developer and do something akin to # struct S : M as had been suggested previously. Sure, that particular syntax may mean something else to some C++ folks, but at least the intent is clear and the /outcome/ is consistent.

When you say "derived from M" are you referring to the ordering/layout of M matching that of the start of S (new fields of S therefore existing in the part of S which is larger than M). I'm not sure "derived" is the right term to use, we don't want to confuse it with class derivation, perhaps saying "S is based on M" is better? /You say potatoes I say ../ As one of the main reasons/uses for structs is to define a specific layout in memory, perhaps the main reason for Walters syntax is to make it possible to define that layout however required.

Another good use for structs is for traits class with little or no data. Mostly just a collection of types and static functions. Having the ability to extend these structs is handy. A library can define a set of base types A, and users can add to or modify it without having to know all the stuff that was in A to begin with. Or vice versa, I define the base and pass that to the library and the library adds a few more things to it. The reason these should be structs is because sometimes you want to add in maybe one or two small data members that control operation. For instance you might have a 'compare' function in the traits and want to parameterize it by a data member to act like either less-than or greater-than. Such things should have value semantics.

The proposed struct inheritance only inherits fields, not methods/functions though, right? Regan
Sep 03 2007
parent BCS <ao pathlink.com> writes:
Reply to Regan,

 Bill Baxter wrote:
 
 The reason these should be structs is because sometimes you want to
 add in maybe one or two small data members that control operation.
 For instance you might have a 'compare' function in the traits and
 want to parameterize it by a data member to act like either less-than
 or greater-than.  Such things should have value semantics.
 

methods/functions though, right?

Why? That's not how I would want to do it.
 
 Regan
 

Sep 03 2007
prev sibling next sibling parent kris <foo bar.com> writes:
Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:
 
     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }
 
 Why not just allow mixin to do this?
 
     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }
 
 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }
 
 Just let us treat a struct like a zero arg template for mixin purposes.
 
 --bb

Perhaps because the alias itself is optional? It just brings the members of 'm' into the namespace of 'S', without requiring an explicit S.m.a dereference. On the other hand, mixin is the work of the devil :p
Aug 30 2007
prev sibling parent reply Reiner Pope <some address.com> writes:
Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:
 
     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }
 
 Why not just allow mixin to do this?
 
     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }
 
 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }
 
 Just let us treat a struct like a zero arg template for mixin purposes.
 
 --bb

Template mixins require that the sourcecode of the template is available to the compiler. Aliases don't. In this sense at least, aliases are cleaner. -- Reiner
Aug 30 2007
next sibling parent reply Don Clugston <dac nospam.com.au> writes:
Reiner Pope wrote:
 Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }

 Why not just allow mixin to do this?

     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }

 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

Template mixins require that the sourcecode of the template is available to the compiler. Aliases don't. In this sense at least, aliases are cleaner. -- Reiner

the Saturday).
Aug 30 2007
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Don,

 Also, Walter wants to get of template mixins. (That was discussed a
 little on the Saturday).
 

WHAT!! They are such a wonderful solution to a number of interesting problems. Unless He plans on having macros take there place I would be vary sad to see them go. will a macro be able to add several function to a class in one shot? Several template alias to another template?
Aug 30 2007
parent Don Clugston <dac nospam.com.au> writes:
BCS wrote:
 Reply to Don,
 
 Also, Walter wants to get of template mixins. (That was discussed a
 little on the Saturday).

WHAT!! They are such a wonderful solution to a number of interesting problems. Unless He plans on having macros take there place I would be vary sad to see them go.

I think that's the idea.
 will a macro be able to add several function to a class in one shot? 
 Several template alias to another template?
 
 

Sep 01 2007
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Don Clugston wrote:
 Reiner Pope wrote:
 Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }

 Why not just allow mixin to do this?

     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }

 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

Template mixins require that the sourcecode of the template is available to the compiler. Aliases don't. In this sense at least, aliases are cleaner. -- Reiner


Just to be clear -- I'm not saying the 'mixin M' should be a shortcut for the similar-looking template mixin. Just suggesting to reuse the keyword for a similar concept. You want to add in the members of another struct and at the same time avoid it looking like polymorphic inheritance.
 Also, Walter wants to get [rid] of template mixins. (That was discussed a 
 little on the Saturday).

Now that's interesting. Replaced by macros? --bb
Aug 31 2007
parent Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Bill Baxter wrote:

 Don Clugston wrote:
 Reiner Pope wrote:
 Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea
 verily it doth say:

     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }

 Why not just allow mixin to do this?

     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }

 That's basically the way it's done now except now it would be more
 like: template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

Template mixins require that the sourcecode of the template is available to the compiler. Aliases don't. In this sense at least, aliases are cleaner.


Just to be clear -- I'm not saying the 'mixin M' should be a shortcut for the similar-looking template mixin. Just suggesting to reuse the keyword for a similar concept. You want to add in the members of another struct and at the same time avoid it looking like polymorphic inheritance.

I like it. It's also more consistent with the previous behavior.
 Also, Walter wants to get [rid] of template mixins. (That was discussed a
 little on the Saturday).

Now that's interesting. Replaced by macros?

Sounds really hilarious since I've always considered mixins to be macros in D. If you look at the new paper, the only differences between 'macro' and template+mixin are a) mixins provide only unhygienic macros, 'macro' has syntax for both cases b) template mixins can only inject declarations c) parameter types and pattern matching What I would like to see is an unification of macros and templates. I don't see any reason why templates cannot have better pattern matching or hygienic invocations. It should be pretty easy to copy that functionality from one's favourite state of the art purely functional language. Hmm, one more thing. The slides only show how pattern matching works with expressions. What about blocks of code? Will it be possible to implement a custom <insert some builtin statement here> with macros? Will all statements in D 2.0 become expressions?
Aug 31 2007
prev sibling parent kris <foo bar.com> writes:
Don Clugston wrote:
 Also, Walter wants to get of template mixins. (That was discussed a 
 little on the Saturday).

Hoorah! Hoorah! :)
Aug 31 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Reiner Pope wrote:
 Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }

 Why not just allow mixin to do this?

     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }

 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

Template mixins require that the sourcecode of the template is available to the compiler. Aliases don't. In this sense at least, aliases are cleaner. -- Reiner

Huh? Explain how the above alias example would work if the compiler doesn't know the source code of what is being aliased: struct M; struct S { M m; alias m this; int b; } It's not even possible to declare m without knowing the source of M! Perhaps I misunderstood you? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 01 2007
parent reply Reiner Pope <some address.com> writes:
Bruno Medeiros wrote:
 Reiner Pope wrote:
 Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }

 Why not just allow mixin to do this?

     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }

 That's basically the way it's done now except now it would be more like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

Template mixins require that the sourcecode of the template is available to the compiler. Aliases don't. In this sense at least, aliases are cleaner. -- Reiner

Huh? Explain how the above alias example would work if the compiler doesn't know the source code of what is being aliased: struct M; struct S { M m; alias m this; int b; } It's not even possible to declare m without knowing the source of M! Perhaps I misunderstood you?

distribute the source code of your implementation, whereas template mixins require that the implementation source is also available. -- Reiner
Sep 01 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Reiner Pope wrote:
 Bruno Medeiros wrote:
 Reiner Pope wrote:
 Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }

 Why not just allow mixin to do this?

     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin purposes.

 --bb

Template mixins require that the sourcecode of the template is available to the compiler. Aliases don't. In this sense at least, aliases are cleaner. -- Reiner

Huh? Explain how the above alias example would work if the compiler doesn't know the source code of what is being aliased: struct M; struct S { M m; alias m this; int b; } It's not even possible to declare m without knowing the source of M! Perhaps I misunderstood you?

distribute the source code of your implementation, whereas template mixins require that the implementation source is also available. -- Reiner

You mean like ? --- foo.di --- struct M { int a; void func(); } --- ---- import foo; struct S { M m; alias m this; int b; } And then linking with a foo.obj that has an implementation for M.func? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 01 2007
parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bruno Medeiros wrote:
 Reiner Pope wrote:
 Bruno Medeiros wrote:
 Reiner Pope wrote:
 Bill Baxter wrote:
 Let us all turn our copies of WalterAndrei.pdf to page 40 where yea 
 verily it doth say:

     struct M { int a; }
     struct S {
        M m;
        alias m this;
        int b;
     }

 Why not just allow mixin to do this?

     struct M { int a; }
     struct S {
        mixin M;
        int b;
     }

 That's basically the way it's done now except now it would be more 
 like:
 template MMixin() { int a; }
 struct M { mixin M; }
 struct S { mixin M; int b; }

 Just let us treat a struct like a zero arg template for mixin 
 purposes.

 --bb

Template mixins require that the sourcecode of the template is available to the compiler. Aliases don't. In this sense at least, aliases are cleaner. -- Reiner

Huh? Explain how the above alias example would work if the compiler doesn't know the source code of what is being aliased: struct M; struct S { M m; alias m this; int b; } It's not even possible to declare m without knowing the source of M! Perhaps I misunderstood you?

distribute the source code of your implementation, whereas template mixins require that the implementation source is also available. -- Reiner

You mean like ? --- foo.di --- struct M { int a; void func(); } --- ---- import foo; struct S { M m; alias m this; int b; } And then linking with a foo.obj that has an implementation for M.func?

Hum, that being the case, then yes it's different, mostly due to the fact that mixin templates always generate new instances of their content, and this "import alias" would not. Another noticeable difference would be if the content had static members: mixin templates would generate new "instances" of the static member, whereas the "import alias" would always refer to the same static member. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 01 2007