Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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 TBase.

...

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)

...

Clearly, Base and 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) Say ().

So 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.
Parrot_BaseCallProxy_SOM3GUID implements IParrot, which
in turn was passed as second parameter to Mixin<TThis, TBase>
for this diagram:

The most important points in the diagram are:

...

A call OnThePhoneMixin's PretendToTalkOnThePhone () to
Base.Say will eventually call Parrot's Say (). Here is
a walk-through for how this works.

  • Base.Say ("Halloh?") delegates to the Say () method in Parrot_BaseCallProxy_SOM3GUID
  • Parrot_BaseCallProxy_SOM3GUID's Say () method delegates to Base_Say () in Parrot_Mixed_SOM3GUID
  • Parrot_Mixed_SOM3GUID's Say () delegates to Parrot's Say () via base.Say ()
    (note the lowercase 'b' in base.Say () – not a typo; Parrot_Mixed_SOM3GUID calls its base-class' Say ()

Why can't Parrot_Mixed_SOM3GUID's own Say () method be called here?
Simple: that's the Say () overridden by the mixin class – the one called
by This.Say ().

"Technical reasons"

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
Base_X method.

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