www.digitalmars.com         C & C++   DMDScript  

D - Mixins

reply Patrick Down <pat codemoon.com> writes:
As I was doing my day job today, writing C++ code
and wishing it was D, I found myself once again wanting 
a feature that neither C++ nor D has.  What I want are 
mixins.  

You will find various explanations of mixins on the web
but to me they are just aggregation with a twist.  The
twist is that aggregated object has some access to the
object in which it is aggregated into.  

I think that with D's templates could be extended to
cover this feature.  My suggested syntax for this
would be.

template Mixin(this)
{
  int foo;

  int AccessAggObj(int a)
  {
    return this.ParentFunc() + foo + a;
  }
}


class UseMixin
{
  int ParentFunc()
  {
    return 12;
  }

  instance Mixin(this) bar;
  // foo and AccessAggObj are
  // made members of the class
  // accessible from bar;
}


UseMixin a = new UseMixin();

a.bar.foo = 5;

a.bar.AccessAggObj(7); // returns 24
Oct 18 2002
parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
Yes.  Wow.  That's alot like the C++ trick of inheriting from a template
that is parameterized with the derived class:

template <class Derived>
class Wierd
{
public:
    int Foo(int a)
    {
        return Derived::Bar(a+1)+4;
    }
};

class Wierder : public Wierd<Wierder>
{
public:
    void Test()
    {
        std::cout << Foo(3); // prints 5
    }
    int Bar(int b) { return b + 2; }
};

Voila!  Method overriding without vtables.  No virtual function table
necessary.  Call functions that only exist in your derived classes.

Why do you need abstract functions?  Just call a function on the derived
class and let the compiler try to figure it out.  If it can't it's an error.

It's a cool trick.  It could certainly use prettier syntax. But your thing
looks like it could be better possibly.

I would want mixins even if it's just inheriting a partial implementation
for an interface that is declared somewhere else.

I like interfaces.  But oftentimes you want to provide some default
implementation.  That's why I like multiple inheritance and mixins.
Otherwise you have to duplicate alot of interfaces (by hand, or cut and
paste) to accomplish the same thing.

Maybe it's more like an inherited "feature" that I want.  Exposing this
packaged feature that you get from somewhere else.  Maybe what I want is to
be able to have a class "merge" another class into itself.

class A
{
    int feature1;
}
class B
{
    int feature2;
    mixin A;
}
void Test()
{
    B b;
    printf(b.feature2);  // ok
    printf(b.feature1);  // ok also
}

Need some way to deal with name conflicts.  But this is almost essentially
Multiple Inheritance.  I could handle it if all conflicts were resolved with
that all of the conflicting declarations has to be abstract (the interface)
and only one must be an implementation.  MI so long as you promise the
compiler there will be no collisions.  If there are collisions you have to
rename something.  So it'd be mainly good for use inside a single component
where you can control use of it.  Not something you want to expose to the
outside world.

Sean

"Patrick Down" <pat codemoon.com> wrote in message
news:Xns92ABA418CB124patcodemooncom 63.105.9.61...
 As I was doing my day job today, writing C++ code
 and wishing it was D, I found myself once again wanting
 a feature that neither C++ nor D has.  What I want are
 mixins.

 You will find various explanations of mixins on the web
 but to me they are just aggregation with a twist.  The
 twist is that aggregated object has some access to the
 object in which it is aggregated into.

 I think that with D's templates could be extended to
 cover this feature.  My suggested syntax for this
 would be.

 template Mixin(this)
 {
   int foo;

   int AccessAggObj(int a)
   {
     return this.ParentFunc() + foo + a;
   }
 }


 class UseMixin
 {
   int ParentFunc()
   {
     return 12;
   }

   instance Mixin(this) bar;
   // foo and AccessAggObj are
   // made members of the class
   // accessible from bar;
 }


 UseMixin a = new UseMixin();

 a.bar.foo = 5;

 a.bar.AccessAggObj(7); // returns 24

Oct 19 2002
parent reply Patrick Down <pat codemoon.com> writes:
"Sean L. Palmer" <seanpalmer directvinternet.com> wrote in
news:aor45k$12of$1 digitaldaemon.com: 

 Yes.  Wow.  That's alot like the C++ trick of inheriting from a
 template that is parameterized with the derived class:

Yes.
 It's a cool trick.  It could certainly use prettier syntax. But your
 thing looks like it could be better possibly.
 
 I would want mixins even if it's just inheriting a partial
 implementation for an interface that is declared somewhere else.
 
 I like interfaces.  But oftentimes you want to provide some default
 implementation.  That's why I like multiple inheritance and mixins.
 Otherwise you have to duplicate alot of interfaces (by hand, or cut
 and paste) to accomplish the same thing.

OOP pays a lot of attention to the "is-a" type relations. It's all about creating abstract interfaces that allow specific objects to be dealt with in a uniform manner. I think perhaps there could be some advances made in dealing with "has-a" type relationships. I'm creating a car object. It has an engine, wheels, body, transmission, etc... I aggregate all these things into the car object and then I spend time wiring together the various inputs and output of the components to each other and the external car interfaces. Why can't there be some help with the wiring process? Why can't an engine expect that it's container implements some sort of throttle control? I see this as another sort of contract in a way. To use an engine you must implement the correct set of inputs and output for it. Anyway I see mixins as sort of a step in this direction.
 
 Maybe it's more like an inherited "feature" that I want.  Exposing
 this packaged feature that you get from somewhere else.  Maybe what I
 want is to be able to have a class "merge" another class into itself.
 
 class A
 {
     int feature1;
 }
 class B
 {
     int feature2;
     mixin A;
 }
 void Test()
 {
     B b;
     printf(b.feature2);  // ok
     printf(b.feature1);  // ok also
 }
 
 Need some way to deal with name conflicts.  But this is almost
 essentially Multiple Inheritance.  I could handle it if all conflicts
 were resolved with that all of the conflicting declarations has to be
 abstract (the interface) and only one must be an implementation.  MI
 so long as you promise the compiler there will be no collisions.  If
 there are collisions you have to rename something.  So it'd be mainly
 good for use inside a single component where you can control use of
 it.  Not something you want to expose to the outside world.

With D, doing mixins with templates does away with the naming conflicts and with all the associated problems with MI. The naming conflicts go away because the D templates require a instance identifier. The MI issues go away because code is not generated until the template is instanced in the class.
Oct 19 2002
next sibling parent "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
So you're advocating generics as being a suitable replacement for MI?

Mayhap...  must think about it.

Sean

"Patrick Down" <pat codemoon.com> wrote in message
news:Xns92AC99CCA95D8patcodemooncom 63.105.9.61...
 "Sean L. Palmer" <seanpalmer directvinternet.com> wrote in
 news:aor45k$12of$1 digitaldaemon.com:

 Yes.  Wow.  That's alot like the C++ trick of inheriting from a
 template that is parameterized with the derived class:

Yes.
 It's a cool trick.  It could certainly use prettier syntax. But your
 thing looks like it could be better possibly.

 I would want mixins even if it's just inheriting a partial
 implementation for an interface that is declared somewhere else.

 I like interfaces.  But oftentimes you want to provide some default
 implementation.  That's why I like multiple inheritance and mixins.
 Otherwise you have to duplicate alot of interfaces (by hand, or cut
 and paste) to accomplish the same thing.

OOP pays a lot of attention to the "is-a" type relations. It's all about creating abstract interfaces that allow specific objects to be dealt with in a uniform manner. I think perhaps there could be some advances made in dealing with "has-a" type relationships. I'm creating a car object. It has an engine, wheels, body, transmission, etc... I aggregate all these things into the car object and then I spend time wiring together the various inputs and output of the components to each other and the external car interfaces. Why can't there be some help with the wiring process? Why can't an engine expect that it's container implements some sort of throttle control? I see this as another sort of contract in a way. To use an engine you must implement the correct set of inputs and output for it. Anyway I see mixins as sort of a step in this direction.
 Maybe it's more like an inherited "feature" that I want.  Exposing
 this packaged feature that you get from somewhere else.  Maybe what I
 want is to be able to have a class "merge" another class into itself.

 class A
 {
     int feature1;
 }
 class B
 {
     int feature2;
     mixin A;
 }
 void Test()
 {
     B b;
     printf(b.feature2);  // ok
     printf(b.feature1);  // ok also
 }

 Need some way to deal with name conflicts.  But this is almost
 essentially Multiple Inheritance.  I could handle it if all conflicts
 were resolved with that all of the conflicting declarations has to be
 abstract (the interface) and only one must be an implementation.  MI
 so long as you promise the compiler there will be no collisions.  If
 there are collisions you have to rename something.  So it'd be mainly
 good for use inside a single component where you can control use of
 it.  Not something you want to expose to the outside world.

With D, doing mixins with templates does away with the naming conflicts and with all the associated problems with MI. The naming conflicts go away because the D templates require a instance identifier. The MI issues go away because code is not generated until the template is instanced in the class.

Oct 19 2002
prev sibling parent Paul Conway <Paul_member pathlink.com> writes:
Some thoughts about mixins based on my experience with the Smallworld Magik
language:

Magik uses mixins as a major and very powerful feature. However it can lead to a
form of confusion that is best avoided. That is, a programmer devising a new
class looks thru a list of mixins and picks a few he thinks he needs, overrides
the functions he does not like, and adds what is missing. He now has a class
that without the mixins would have taken him a lot longer to write. However the
possibilities for laziness abound. If a class needs some functionality added,
just add a mixin; and this can go on and on. Adding is easy. Pruning out what is
not needed is the hard part.

Mixins tend to provide everything including the kitchen sink, ie far more than
is required in many cases, simply because they were written, with the best
intentions, for maximum flexibility and usefulness. And all those functions you
don't use are sitting there waiting to confuse a maintenance programmer because
he may not have a clue as to which ones are surplus to requirements. Ones that
ought never to be called are still available. He cannot therefore just pull out
a few mixins that don't look important. He might cause unexpected problems at
run-time (which is when the linkages to mixin functions get automatically cached
on-demand, in Magik). In D, the same problem would occur at compile-time.

Magik allows multiple-inheritance. Though it is easy enough to do, out of
thousands of object classes, a mere handful have ever used it, and could be
rewritten to not do so. The availability of mixins made the use of
multiple-inheritance effectively unnecessary and, if this had been known when
the code base development began, the multiple-inheritance feature might well
have been removed from the compiler.
Jan 19 2003