Thread overview
Multiple Inheritance, Mixins, and Constructors
May 19, 2009
Chris Williams
May 19, 2009
Ary Borenszweig
May 20, 2009
Chris Williams
May 19, 2009
Well so I had a case where I needed to do something like multiple inheritance. Here's an example solution:

interface IFoo {
   void bar();
}
template TFoo() {
   void bar() {
      // code
      // ...
   }
}

class Base {
   // variables
}

class Thing : Base, IFoo {
   mixin TFoo;
}

Well so that's all well and good. The problem comes if I have an object declared in TFoo. For instance:

template TFoo() {
   SomeObject s_o;

   void bar() {
      s_o.x = 10;

      // code
      // ...
   }
}

It compiles fine, but when I go to run it, trying to set so.x gets an error because s_o hasn't been instantiated. If I try:

template TFoo() {
   SomeObject s_o = new SomeObject();

   void bar() {
      s_o.x = 10;

      // code
      // ...
   }
}

Then I get a compile-time error that I can't do that. Now I'd love to define a constructor in TFoo that instantiated s_o, but I'm pretty sure that would conflict should anyone try to add a constructor to (for instance) class Thing.

My solution was to add an initFoo() definition in IFoo, and say that it needs to be called in the constructor of anyone using IFoo/TFoo, but that seems pretty wonky. Admittedly the whole interface/mixin thing is already a bit wonky, but it seems like there should be a solution to at least the object initialization problem.
May 19, 2009
Chris Williams escribió:
> Well so I had a case where I needed to do something like multiple inheritance. Here's an example solution:
> 
> interface IFoo {
>    void bar();
> }
> template TFoo() {
>    void bar() {
>       // code
>       // ...
>    }
> }
> 
> class Base {
>    // variables
> }
> 
> class Thing : Base, IFoo {
>    mixin TFoo;
> }
> 
> Well so that's all well and good. The problem comes if I have an object declared in TFoo. For instance:
> 
> template TFoo() {
>    SomeObject s_o;
> 
>    void bar() {
>       s_o.x = 10;
>             // code
>       // ...
>    }
> }
> 
> It compiles fine, but when I go to run it, trying to set so.x gets an error because s_o hasn't been instantiated. If I try:
> 
> template TFoo() {
>    SomeObject s_o = new SomeObject();
> 
>    void bar() {
>       s_o.x = 10;
>             // code
>       // ...
>    }
> }
> 
> Then I get a compile-time error that I can't do that. Now I'd love to define a constructor in TFoo that instantiated s_o, but I'm pretty sure that would conflict should anyone try to add a constructor to (for instance) class Thing.
> 
> My solution was to add an initFoo() definition in IFoo, and say that it needs to be called in the constructor of anyone using IFoo/TFoo, but that seems pretty wonky. Admittedly the whole interface/mixin thing is already a bit wonky, but it seems like there should be a solution to at least the object initialization problem.

You can do this:

template TFoo() {
	// Never use this variable directly :-P
	SomeObject _s_o;

	SomeObject s_o() {
		if (_s_o is null)
			_s_o = new SomeObject();
		return _s_o;
	}

	// And if you want to make it assignable too
	SomeObject s_o(SomeObject x) {
		_s_o = x;
	}
	
	void bar() {
		s_o.x = 10;
		// code
		// ...
	}
}
May 20, 2009
Ary Borenszweig Wrote:

> 
> You can do this:
> 
> template TFoo() {
> 	// Never use this variable directly :-P
> 	SomeObject _s_o;
> 
> 	SomeObject s_o() {
> 		if (_s_o is null)
> 			_s_o = new SomeObject();
> 		return _s_o;
> 	}
> 
> 	// And if you want to make it assignable too
> 	SomeObject s_o(SomeObject x) {
> 		_s_o = x;
> 	}
> 
> 	void bar() {
> 		s_o.x = 10;
> 		// code
> 		// ...
> 	}
> }

Well I ended up converting my object to a struct, which solved the issue. Your solution would probably work, but for what I'm doing, I'd rather not incur the overhead of a branch and (possible) function call for every access of the object.

It seems like object initialization outside of a method should be magically moved to the top of the constructor. But ah well.

Thank you.