www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Mixins & init code, others

reply Mike Swieton <mike swieton.net> writes:
It would be extremely useful to have mixins have constructors for some
initialization, i.e. a constructor. Has anyone figured out how to do this?
I've come up with some cheap hack solutions, but nothing that really works
well. I'd settle for "mixin ctor code is lexically composed with each ctor of
the mixed class". But a little ability for initializing the data would be
extremely handy.

A second, and most likely more important item: mixins need to support
invariants. The above is much less important if I can use an invariant to
inforce that a manually called init method has been called. This also should
not be complex: a lexical composition would work perfectly fine (although
scoping rules would have to be determined).

Has anyone thought about this? The lack of ctors and invariants I think
somewhat limits the utility of mixing classes, because one cannot provide good
initialization of data in any way.

Mike Swieton
__
Computer Science is the only discipline in which we view adding a new wing to
a building as being maintenance.
	- Jim Horning
May 17 2004
next sibling parent "fred" <info fleet-manage.com> writes:
"Mike Swieton" <mike swieton.net> wrote in message
news:pan.2004.05.18.02.44.03.517824 swieton.net...
 It would be extremely useful to have mixins have constructors for some
 initialization, i.e. a constructor. Has anyone figured out how to do this?
 I've come up with some cheap hack solutions, but nothing that really works
 well. I'd settle for "mixin ctor code is lexically composed with each ctor of
 the mixed class". But a little ability for initializing the data would be
 extremely handy.
How about something like this ?? class Part { this(int param) { v = param; } int Value() { return v; } private: int v; } template Construct!( T, alias param ) { T part = new T(param); } class Some { this(int param) { x = param; } private: int x; mixin Construct!( Part, x*2 ) part; } int main() { Some some(5); return some.part.Value(); // will return 10 }
 A second, and most likely more important item: mixins need to support
 invariants. The above is much less important if I can use an invariant to
 inforce that a manually called init method has been called. This also should
 not be complex: a lexical composition would work perfectly fine (although
 scoping rules would have to be determined).

 Has anyone thought about this? The lack of ctors and invariants I think
 somewhat limits the utility of mixing classes, because one cannot provide good
 initialization of data in any way.
Have you got any code that could explain this further ? cheers fred
May 17 2004
prev sibling next sibling parent reply "Walter" <newshound digitalmars.com> writes:
Actually, you can mix in constructors. Just put a 'this' method in the
template.

"Mike Swieton" <mike swieton.net> wrote in message
news:pan.2004.05.18.02.44.03.517824 swieton.net...
 It would be extremely useful to have mixins have constructors for some
 initialization, i.e. a constructor. Has anyone figured out how to do this?
 I've come up with some cheap hack solutions, but nothing that really works
 well. I'd settle for "mixin ctor code is lexically composed with each ctor
of
 the mixed class". But a little ability for initializing the data would be
 extremely handy.

 A second, and most likely more important item: mixins need to support
 invariants. The above is much less important if I can use an invariant to
 inforce that a manually called init method has been called. This also
should
 not be complex: a lexical composition would work perfectly fine (although
 scoping rules would have to be determined).

 Has anyone thought about this? The lack of ctors and invariants I think
 somewhat limits the utility of mixing classes, because one cannot provide
good
 initialization of data in any way.

 Mike Swieton
 __
 Computer Science is the only discipline in which we view adding a new wing
to
 a building as being maintenance.
 - Jim Horning
May 17 2004
next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Walter wrote:
 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
I think he means something like this: (which does not work) template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this() { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } I think this is part of the can of worms that Matthew was talking about* when he suggested not allowing mixins to add attributes. Not only do mixins require constructors, they need to have invariants as well. * here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/133 -- andy
May 17 2004
next sibling parent reply Roel Mathys <roel.mathys yucom.be> writes:
Andy Friesen wrote:

 Walter wrote:
 
 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
I think he means something like this: (which does not work) template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this() { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } I think this is part of the can of worms that Matthew was talking about* when he suggested not allowing mixins to add attributes. Not only do mixins require constructors, they need to have invariants as well. * here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/133 -- andy
this does work, template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this(int x) { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } mayb it would be better if a this defined this way somehow magically attaches itself to the original ctor, bye, roel ps: the only place I like magic is in a good book
May 17 2004
parent reply Roel Mathys <roel.mathys yucom.be> writes:
Roel Mathys wrote:

 Andy Friesen wrote:
 
 Walter wrote:

 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
I think he means something like this: (which does not work) template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this() { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } I think this is part of the can of worms that Matthew was talking about* when he suggested not allowing mixins to add attributes. Not only do mixins require constructors, they need to have invariants as well. * here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/133 -- andy
this does work, template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this(int x) { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } mayb it would be better if a this defined this way somehow magically attaches itself to the original ctor, bye, roel ps: the only place I like magic is in a good book
something like this, please don't flame for abusing some feature :-) template Mix1() { void Mix1() { printf("mix1\n"); } } template Mix2() { void Mix2() { printf("Mix2!\n"); } } class Bar { int myx; this() in { mixin Mix1; Mix1(); } out { mixin Mix2; Mix2(); } body { myx = 15; } } int main() { Bar bar = new Bar(); return 0; } bye, roel
May 17 2004
parent Roel Mathys <roel.mathys yucom.be> writes:
Roel Mathys wrote:

 Roel Mathys wrote:
 
 Andy Friesen wrote:

 Walter wrote:

 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
I think he means something like this: (which does not work) template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this() { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } I think this is part of the can of worms that Matthew was talking about* when he suggested not allowing mixins to add attributes. Not only do mixins require constructors, they need to have invariants as well. * here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/133 -- andy
this does work, template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this(int x) { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } mayb it would be better if a this defined this way somehow magically attaches itself to the original ctor, bye, roel ps: the only place I like magic is in a good book
something like this, please don't flame for abusing some feature :-) template Mix1() { void Mix1() { printf("mix1\n"); } } template Mix2() { void Mix2() { printf("Mix2!\n"); } } class Bar { int myx; this() in { mixin Mix1; Mix1(); } out { mixin Mix2; Mix2(); } body { myx = 15; } } int main() { Bar bar = new Bar(); return 0; } bye, roel
apparantly, the mixin's must be directly in the scope of class, then you can access members of the class bye, roel ---------------------------------------------------- template Mix1() { void Mix1() { myx = 1; }} template Mix2() { void Mix2() { myx = 2; }} class Bar { int myx; mixin Mix1; mixin Mix2; this() in { Mix1(); } out { Mix2(); } body { myx = 15; } } int main() { Bar bar = new Bar(); printf("myx = %d\n",bar.myx); return 0; }
May 17 2004
prev sibling next sibling parent "Vathix" <vathixSpamFix dprogramming.com> writes:
"Andy Friesen" <andy ikagames.com> wrote in message
news:c8c76s$2cvn$1 digitaldaemon.com...
 Walter wrote:
 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
I think he means something like this: (which does not work) template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this() { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } I think this is part of the can of worms that Matthew was talking about* when he suggested not allowing mixins to add attributes. Not only do mixins require constructors, they need to have invariants as well. * here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/133 -- andy
How about constructors without parameter lists are implicitly called in order (as well as destructors), and if they take parameters, you have to have your constructor call them. Like this: template Mix1() { this() { printf("mix1\n"); } } template Mix2(int stuff) { // Note the parameter list. this(int stuff) { printf("Mix2!\n"); } ~this() { /* stuff */ } } class Bar { mixin Mix1; mixin Mix2; this() { // Mix1.this() // Implied. Mix2.this(4); // Required. } // ~this() { Mix2.~this(); } // Implied, or implicitly added to the end of an existing destructor. } If you have a long complicated mixin like Foo!(Stuff!(a, b, c!(d, e), f!(etc))) then just alias it. aliasname.this(...). Or if it has a mixin identifier then you can just use that name. Constructors aren't like normal functions, you can't mix them in like a regular function because all initializations need to occur.
May 17 2004
prev sibling next sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
I guess the solution might be...and I agree that it's suboptimal:

template Mix1() {
   void init() { ... }
}
template Mix2() {
   void init() { ... }
}
class Bar {
   mixin Mix1 M1;
   mixin Mix2 M2;
   this() {
     M1.init();
     M2.init();
   }
}

Of course, it would be nice to not have to call this by hand, but this 
way you can call init() with arguments if you wanted.

Andy Friesen wrote:
 Walter wrote:
 
 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
I think he means something like this: (which does not work) template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this() { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } I think this is part of the can of worms that Matthew was talking about* when he suggested not allowing mixins to add attributes. Not only do mixins require constructors, they need to have invariants as well. * here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/133 -- andy
May 18 2004
prev sibling parent Kevin Bealer <Kevin_member pathlink.com> writes:
In article <c8c76s$2cvn$1 digitaldaemon.com>, Andy Friesen says...
Walter wrote:
 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
I think he means something like this: (which does not work) template Mix1() { this() { printf("mix1\n"); } } template Mix2() { this() { printf("Mix2!\n"); } } class Bar { mixin Mix1; mixin Mix2; } int main() { Bar bar = new Bar(); return 0; } I think this is part of the can of worms that Matthew was talking about* when he suggested not allowing mixins to add attributes. Not only do mixins require constructors, they need to have invariants as well. * here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/133 -- andy
If something is complex enough to need constructors then perhaps it is better not to mix it, but to just include it as a regular member field. If it has a constructor, does that imply that it has a "this" pointer? If so, it could be assigned to another field somewhere; the GC has to keep it around, so it would be better as a seperate object, maybe. Not to disagree; but the actual purposes of the mixing are not clear to me. It seems like a useful feature, but when to use and when not? I dunno yet. Kevin
May 18 2004
prev sibling parent reply Michael Coupland <mcoupland hmc.edu> writes:
Walter wrote:
 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
That still doesn't work very well if your goal is to guarantee that your constructor is executed. (A handy thing to have happen...) I was just playing around with mixins, and the following code demonstrates the problem: ---------- template MixVar() { this() { mixed_var = 1; } int mixed_var; } class MixTarg { this( ) { targ_var = 2; } int targ_var; mixin MixVar; void print() { printf( "(%d, %d)", targ_var, mixed_var ); } } int main( char[][] args ) { MixTarg test = new MixTarg(); test.print(); return 0; } ---------- The output is: (2, 0) Rather than the (expected? hoped-for?): (2, 1) So I guess the question is, is there a way to have the mixin's constructor called /in addition to/ whatever constructor is called for the base class. (The current way you can merely supply new constructors, and (as this example shows) they won't override any existing constructors of identical signature. Michael
May 17 2004
next sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Michael Coupland" <mcoupland hmc.edu> wrote in message
news:c8c8dp$2f2v$1 digitaldaemon.com...
 Walter wrote:
 Actually, you can mix in constructors. Just put a 'this' method in the
 template.
That still doesn't work very well if your goal is to guarantee that your constructor is executed. (A handy thing to have happen...) I was just playing around with mixins, and the following code demonstrates the
problem:
 ----------

 template MixVar()
 {
 this() { mixed_var = 1; }
 int mixed_var;
 }

 class MixTarg
 {
 this( ) { targ_var = 2; }
 int targ_var;
 mixin MixVar;

 void print() { printf( "(%d, %d)", targ_var, mixed_var ); }
 }

 int main( char[][] args )
 {
 MixTarg test = new MixTarg();
 test.print();
 return 0;
 }

 ----------

 The output is:
 (2, 0)
 Rather than the (expected? hoped-for?):
 (2, 1)

 So I guess the question is, is there a way to have the mixin's
 constructor called /in addition to/ whatever constructor is called for
 the base class. (The current way you can merely supply new constructors,
 and (as this example shows) they won't override any existing
 constructors of identical signature.
What is happening here is any declarations in the current scope *override* declarations in a mixin scope when looking at it from outside the mixin. The idea is to have a generic version in the mixin, and perhaps a customized version to override it. Mixins aren't classes or structs. They're merely a list of declarations that acquire meaning *after* they are mixed in, and they take on meaning based on where they are mixed in, i.e. becoming struct members, class members, local variables, etc.
May 18 2004
parent reply Ben Hinkle <bhinkle4 juno.com> writes:
[snip]
 Mixins aren't classes or structs.
[snip] This is a key point. The doc should have a table or paragraph explaining the different behaviors. Something like features class struct template interface constructor yes no no no member fcns yes yes yes decls-only data members yes yes yes no inheritance single no no multiple instantiable yes yes no no defines a type yes yes no yes mixin no no yes no cls invariants yes no no no Also it would be nice to know what techniques people use to fill in some of those pesky "no"s.
May 18 2004
parent "Walter" <newshound digitalmars.com> writes:
"Ben Hinkle" <bhinkle4 juno.com> wrote in message
news:c8d08c$krr$1 digitaldaemon.com...
 [snip]
 Mixins aren't classes or structs.
[snip] This is a key point. The doc should have a table or paragraph explaining
the
 different behaviors. Something like

  features      class   struct   template   interface
 constructor     yes      no      no       no
 member fcns     yes      yes     yes      decls-only
 data members    yes      yes     yes      no
 inheritance     single   no      no       multiple
 instantiable    yes      yes     no       no
 defines a type  yes      yes     no       yes
 mixin           no       no      yes      no
 cls invariants  yes      no      no       no

 Also it would be nice to know what techniques people use to fill in some
of
 those pesky "no"s.
The table is a good idea, but it doesn't resolve this particular problem. You *can* write a constructor in a mixin, it just becomes the constructor for the enclosing class if it is mixed into a class, and an error if mixed into something else. Also, that constructor can be overridden in the mixed class. Think of mixins like embryonic 'stem cells' that differentiate into muscle, bone, nerve, etc., based on where in the body they find themselves <g>.
May 18 2004
prev sibling parent Norbert Nemec <Norbert.Nemec gmx.de> writes:
What about this:

-------------------------------
template MixVar()
{
        int mixed_var = 1;
}

class MixTarg
{
        int targ_var = 2;
        mixin MixVar;
        
        void print() { printf( "(%d, %d)", targ_var, mixed_var ); }
}

int main( char[][] args )
{
        MixTarg test = new MixTarg();
        test.print();
        return 0;
}
------------------------------

Finding a way to assemble constructors from different parts will be
extremely complicated. Default arguments are not as flexible as code in a
constructor, but they should be sufficient in most cases.
May 18 2004
prev sibling parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
I think, there is a simple solution for this:

* allowing multiple invariants in one class should not be a trivial change
to the language and the compiler.

* instead of thinking of constructors in mixins, you should consider using
default values for class member variables. Of course, default values are not
as flexible as code in a constructor, but finding a way to extend the
language to assemble a constructor automatically from different routines
will be awfully difficult.




Mike Swieton wrote:

 It would be extremely useful to have mixins have constructors for some
 initialization, i.e. a constructor. Has anyone figured out how to do this?
 I've come up with some cheap hack solutions, but nothing that really works
 well. I'd settle for "mixin ctor code is lexically composed with each ctor
 of the mixed class". But a little ability for initializing the data would
 be extremely handy.
 
 A second, and most likely more important item: mixins need to support
 invariants. The above is much less important if I can use an invariant to
 inforce that a manually called init method has been called. This also
 should not be complex: a lexical composition would work perfectly fine
 (although scoping rules would have to be determined).
 
 Has anyone thought about this? The lack of ctors and invariants I think
 somewhat limits the utility of mixing classes, because one cannot provide
 good initialization of data in any way.
 
 Mike Swieton
 __
 Computer Science is the only discipline in which we view adding a new wing
 to a building as being maintenance.
 - Jim Horning
May 18 2004
parent reply Mike Swieton <mike swieton.net> writes:
On Tue, 18 May 2004 15:15:16 +0200, Norbert Nemec wrote:

 I think, there is a simple solution for this:
 
 * allowing multiple invariants in one class should not be a trivial change
 to the language and the compiler.
I'm not sure what you mean. I think you have your logic inverted, perhaps?
 * instead of thinking of constructors in mixins, you should consider using
 default values for class member variables. Of course, default values are not
 as flexible as code in a constructor, but finding a way to extend the
 language to assemble a constructor automatically from different routines
 will be awfully difficult.
It is true that automatically assembling a constructor is probably a bad idea. Not well thought out on my part. The specific limitation that gets me is that I have no way of instantiating a class in a mixin as part of initialization, if I don't want to use an init() method. I dislike init() methods because they do the job of a constructor. I'd prefer a syntax like: mixin Foo(args), perhaps. I'm somewhat tempted to suggest allowing code like: class X { Object x = new Object; // forbidden now } Even though I know many reasons not to want this. However, allowing for this would solve every deficiency I see. Not perfectly (to be honest, I want something more like MI, though I understand why that's not really feasible). Mike Swieton __ Go on, get out. Last words are for fools who haven't said enough. - Karl Marx, last words
May 18 2004
parent Norbert Nemec <Norbert.Nemec gmx.de> writes:
Mike Swieton wrote:

 On Tue, 18 May 2004 15:15:16 +0200, Norbert Nemec wrote:
 
 I think, there is a simple solution for this:
 
 * allowing multiple invariants in one class should not be a trivial
 change to the language and the compiler.
I'm not sure what you mean. I think you have your logic inverted, perhaps?
True, sorry, editing that sentence a few times, it got screwed up completely. What I meant: * allowing multiple invariants in one class *should* be a trivial change to the language and the compiler.
 It is true that automatically assembling a constructor is probably a bad
 idea. Not well thought out on my part.
Thinking again, maybe not. See below.
 The specific limitation that gets me is that I have no way of
 instantiating a class in a mixin as part of initialization, if I don't
 want to use an init() method. I dislike init() methods because they do the
 job of a constructor. I'd prefer a syntax like: mixin Foo(args), perhaps.
 I'm somewhat tempted to suggest allowing code like:
 
 class X
 {
 Object x = new Object; // forbidden now
 }
 
 Even though I know many reasons not to want this. However, allowing for
 this would solve every deficiency I see. Not perfectly (to be honest, I
 want something more like MI, though I understand why that's not really
 feasible).
One alternative to that might be to allow "class initializers" in addition to constructors. Like: class X { Object x; initialize { x = new Object; } ~this() { delete x; } Object y; initialize { y = new Object; } ~this() { delete y; } this() { do_something(); } this(int x) { so_some_other_thing(); } } These initializers would than just be called in order of appearance before the code of a constructor is called. There still is you could still define different constructors with zero or more arguments, but any initialization that is independant of these arguments could be moved out of the constructor into a initializer. For destructors, the situation is simpler: They do not take any arguments, so there is no problem to allow multiple destructors in one class which are then simply concatenated in *reverse* order of appearance.
May 18 2004