If we want to access base members from the target class in the mixin class, we must use the generic
Mixin<TThis, TBase> type, i.e. we must provide a parameter for
As the wiki page
re-motion mixins basics -- the generic 'Mixin' type
explains, "for technical reasons" you are constrained to pass an interface as
TBase parameter. This wiki page explains this constrain and how data is organized at run-time.
As soon as
TBase enters the picture, we face a complication, because then the mixed class ("Parrot_Mixed_SOM3GUID") can have two versions of each target method:
- the one overridden by the mixin class (e.g.
Say (string s)
- the original method from the target class (that would be
Base.Say (string s) when seen from the mixin class)
Now look at this code snippet:
public void PretendToTalkOnThePhone ()
This.Say ("Halloh?"); // overridden 'Say'
Base.Say ("Hi!"); // original (base) 'Say'
This can't hold a reference to the same instance of the mixed class, because that would make the overridden
Say () the same as the original (base)
Base holds a reference to a different instance – a so-called base call proxy. Another synthesized class enters the UML picture, in this example
Parrot_BaseCallProxy_SOM3GUID (labeled "Parrot_BaseCallProxy..." in the illustration).
It is an inner class to
Parrot_Mixed_SOM3GUID and holds a reference to its nesting class. Remember that you can't pass classes as a
TBase parameter to
TThis, only interfaces.
IParrot, which in turn was passed as second parameter to
Mixin<TThis, TBase> for this diagram:
The most important points in the diagram are:
OnThePhoneMixin holds a reference to
Parrot_BaseCallProxy_SOM3GUID (labeled "Parrot_BaseCallProxy..." in the illustration) in
Parrot_BaseCallProxy_SOM3GUID holds a reference to the mixed class
Parrot_Mixed_SOM3GUID (labeled "Parrot_SOM3GUID")
IParrot (note that, in this diagram,
Parrot_Mixed_SOM3GUID do not}}
Parrot_Mixed_SOM3GUID has been endowed with a
PretendToTalkOnThePhone () to
Base.Say will eventually call
Say (). Here is a walk-through for how this works.
Base.Say ("Halloh?") delegates to the
Say () method in
Say () method delegates to
Base_Say () in
Say () delegates to
Say () via
base.Say () (note the lowercase 'b' in
base.Say () – not a typo;
Parrot_Mixed_SOM3GUID calls its base-class'
Say () method be called here? Simple: that's the
Say () overridden by the mixin class – the one called by
As promised in the opening of this wiki page, a word on the technical reasons why you can't pass a class as type parameter to
Mixin<TThis, TBase>. The problem is that you basically need two instances to delegate to – one for the
Base property, one for the
This property. Two instances mean two instantiations, and instantiations can have side-effects (dumping to the screen, opening a socket, new thread, etc.) If the
ObjectFactory would cause two such side effects for each instantiation of the desired target class, the programmer using mixins could get into trouble and would have a hard time figuring out why. Having an
ObjectFactory create two instances instead of one is more tasteless prank than sound engineering, so that's a no-go. The base-call proxy class synthesized at run-time has no side-effects upon instantiation, and no state. It simply steals the interface signatures (
IParrot, in this example) and delegates every method (and every property) implementation to the mixed class – either to the corresponding method (if no call to a base method is needed) or the corresponding
Note that the construction of the two implementor classes works differently for each interface if you pass TWO interfaces to
Mixin<TThis, TBase>, as in
Mixin<IParrot, IParrot>, for example. This call is equivalent to
Mixin<Parrot, IParrot>, because re-motion mixin is smart enough to do the right thing here:
- for the first
IParrot, the object factory finds
Parrot as the implementor and subclasses it to the mixed class
- for the second
IParrot, the object factory generates the base call proxy with no life of its own, delegating everything to the mixed class