New concept Mixin Methods

WebFreak001 d.forum at webfreak.org
Wed Dec 28 12:57:36 UTC 2022


On Sunday, 25 December 2022 at 11:07:30 UTC, Andre Pany wrote:
> Hi,
>
> Since a few days I think about a new concept called Mixin 
> Methods.
> I wonder whether it makes sense to write a DIP or I maybe miss 
> an obvious issue with the concept?
>
> Mixin Methods serves the purpose to enable introspection in 
> class based frameworks by inheritance.
>
> If you look at frameworks like d-unit 
> (https://github.com/linkrope/dunit/blob/master/example.d) or 
> arsd.jni (https://arsd-official.dpldocs.info/arsd.jni.html) 
> they try to solve the issues in different ways.
> In d-unit the unit test classes do not have inheritance but 
> each unit test class needs to add a mixin statement `mixin 
> UnitTest;`.
>
> In arsd.jni there is another concept, the classes inherits 
> introspection by inheriting from the root class and the current 
> class as template parameter:
>
> ```d
> final class Hello : JavaClass!("", Hello) {
> }
> ```
> The issue with this concept is, all classes inherits from the 
> root class (JavaClass) directly. Inheritance from another child 
> class (e.g. Hello) is not possible.
>
> The concept Mixin Methods can be used like this
>
> ```d
> import std;
> void main()
> {
>    new Animal().fancyMethod();
>    new Dog().fancyMethod();
>    new Bulldog().fancyMethod();
> }
>
> class Animal {
>
>     mixin void fancyMethod(){
>         writeln(__traits(identifier, typeof(this)));
>     }
>
> }
>
> class Dog : Animal {}
>
> class Bulldog : Dog {}
> ```
>
> Due to the mixin statement, the compiler will copy the 
> fancyMethod into all sub classes of class Animal as method 
> overload.
>
> ```d
> class Dog : Animal {
> // compiler
> override void fancyMethod(){
> writeln(__traits(identifier, typeof(this)));
> }
> // compiler
> }
>
> class Bulldog : Dog {
> // compiler
> override void fancyMethod(){
> writeln(__traits(identifier, typeof(this)));
> }
> // compiler
> }
> ```
>
> As you can see, Mixin Methods works for non static and non 
> final methods. The benefit is, the users just need to inherit 
> from a framework class to inherit the introspection 
> capabilities.
>
> Does it make sense to create here a DIP or do you see any road 
> blocker?
>
> Kind regards
> Andre

We have the template this parameter that would on the surface 
work like this feature:

```d
import std;
void main()
{
   new Animal().fancyMethod();
   new Dog().fancyMethod();
   new Bulldog().fancyMethod();
}

class Animal {

     void fancyMethod(this This)(){
         writeln(__traits(identifier, This));
     }

}

class Dog : Animal {}

class Bulldog : Dog {}
```

outputs

```
Animal
Dog
Bulldog
```

overriding works by redeclaring the method inside the sub-classes.

However the problem with this is that the methods are just 
templates, e.g. they work like UFCS functions, only knowing the 
type they are being called on and not the actual type. If you 
cast your Bulldog to Animal, you will call fancyMethod with 
`Animal` as template parameter here. (breaking a bunch of OOP 
patterns and the advantages of using inheritance)

I think some mixin-into-subclasses approach would be quite nice 
for a lot of things, but I think it's better if the user needs to 
explicitly `mixin` extra methods, so that they don't magically 
appear. (+ explicit mixin can specify extra options)

Having some way to require users to mixin something would be 
something worth looking into though I think. With methods you 
can, at least for types directly inheriting from the abstract 
class, rely on linker errors. This doesn't scale well though, as 
it will introduce runtime bugs once inheriting from other classes 
that have implementations.


More information about the Digitalmars-d mailing list