Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use mixins and when to use interfaces in Dart?

I'm very familiar with the concepts of interfaces and abstract classes, but not super familiar with the concepts of mixins.

Right now, in Dart, every class A defines an implicit interface, which can be implemented by another class B by using the implements keyword. There's no explicit way of declaring interfaces as, for example, in Java, where an interface contains only unimplemented methods (and eventually static variables). In Dart, since interfaces are defined by classes, the methods of the interface A may actually already be implemented, but the class that implements B still needs to override these implementations.

We can see that situation from the following piece of code:

class A {   void m() {     print("method m");   } }  // LINTER ERROR: Missing concrete implementation of A.m // Try implementing missing method or make B abstract. class B implements A { } 

In Dart, a mixin is also defined via ordinary class declarations...

... In principle, every class defines a mixin that can be extracted from it. However, in this proposal, a mixin may only be extracted from a class that has no declared constructors. This restriction avoids complications that arise due to the need to pass constructor parameters up the inheritance chain.

A mixin is basically a class that can define both unimplemented or implemented methods. It's a way to add methods to another class without needing to logically use inheritance. In Dart, a mixin is applied to a super class, that is extended via "normal" inheritance, like in the following example:

class A {   void m() {     print("method m");   } }  class MyMixin {   void f(){     print("method f");   } }  class B extends A with MyMixin { } 

In this case, we should note that B does not have to implement any further methods both of A and MyMixin.

There's a clear distinction between applying a mixin to a class and inheriting from a class, at least in a language that supports only single-parent inheritance, since, in that case, we could apply many mixins to a class, but a class could just inherit from another class.

There's also a clear distinction between implementing an interface and inheriting from a class. The class that implements an interface needs to mandatorily implement all methods defined by the interface.

So, in summary, the concept of implementing an interface is more about establishing a contract with the class that implements the interface, and the concept of mixins (as the name suggests) is more about reusing code (without recurring to an inheritance hierarchy).

When to use mixins and when to use interfaces in Dart? Are there some rules of thumb for at least special recurrent patterns when designing software where it would be better to define a mixin and applying it to a super class rather than making our class implement an interface? I would appreciate concrete examples of design decisions in a context where both interfaces and mixins could be used, but one is used over the other (for some reason).

like image 579
nbro Avatar asked Aug 27 '17 02:08

nbro


People also ask

Why we use mixin in Dart?

Mixins are awesome because they solve a basic problem that comes with inheritance. They are an elegant way to reuse code from different classes that don't quite fit into the same class hierarchy. A mixin is a class whose methods and properties can be used by other classes – without subclassing.

What is the difference between mixin and interface?

Mixins are hailed as interfaces with behavioral reuse, more flexible interfaces, and more powerful interfaces. You will notice all these have the term interface in them, referring to the Java and C# keyword. Mixins are not interfaces. They are multiple inheritance.

In which of the below cases you would use mixin?

Mixins can be used in two ways, the first case is when we want to make use of class code in such a way that the class doesn't have any constructor and the object of the class is extended. In such a case, we use the with keyword.

What is the use of mixins in Flutter?

Mixins are a way of reusing a class's code in different class hierarchies. For example, you might have a class called Employee which has methods like clockIn . The code in those classes may be useful for both Bartender and Nurse .


2 Answers

Mixins is all about how a class does what it does, it's inheriting and sharing concrete implementation. Interfaces is all about what a class is, it is the abstract signature and promises that the class must satisfy. It's a type.

Take a class that is implemented as class MyList<T> extends Something with ListMixin<T> .... You can use this class as MyList<int> l = new MyList<int>(); or List<int> l = new MyList<int>(), but you should never write ListMixin<int> l = new MyList<int>(). You can, but you shouldn't, because that is treating ListMixin as a type, and it really isn't intended as one. It's the same reason you should always write Map m = new HashMap(); and not HashMap m = new HashMap(); - the type is Map, it's an implementation detail that it's a HashMap.

If you mix in a class (or rather, the mixin derived from a class), then you get all the concrete members of that class in your new mixin class. If you implement a class (or rather, the implicit interface of a class), then you get no concrete members at all, but the abstract signature becomes part of your interface.

Some classes can be used as both, but you should only ever use a class as a mixin if it is intended to be used as a mixin (and documented as such). There are many changes that an class author can do to a class that would break their use as a mixin. We don't want to disallow any such change, which could be perfectly reasonable changes for a non-mixin class, so using a non-mixin class as a mixin is fragile and likely to break in the future.

On the other hand, a class intended to be used as a mixin is usually all about implementation, so it is likely that there is a similar interface declared as well, and that's what you should use in the implements clause.

So, if you want to implement a list, you can either implement the List class and do all the implementation yourself, or mix in the ListMixin class to reuse some base functionality. You can still write implements List<T>, but you get that by inheritance from ListMixin.

Mixins is not a way to get multiple inheritance in the classical sense. Mixins is a way to abstract and reuse a family of operations and state. It is similar to the reuse you get from extending a class, but it is compatible with single-inheritance because it is linear. If you have multiple inheritance, your class has two (or more) superclasses, and you need to handle conflicts between them, including diamond inheritance, in some way.

Mixins in Dart work by creating a new class that layers the implementation of the mixin on top of a superclass to create a new class - it is not "on the side" but "on top" of the superclass, so there is no ambiguity in how to resolve lookups.

Example:

class Counter {   int _counter = 0;   int next() => ++_counter; } class Operation {   void operate(int step) { doSomething(); } } class AutoStepOperation extends Operation with Counter {   void operate([int step]) {     super.operate(step ?? super.next());   } } 

What really happens is that you create a new class "Operation with Counter". It's equivalent to:

Example:

class Counter {   int _counter = 0;   int next() => ++_counter; } class Operation {   void operate(int step) { doSomething(); } } class $OperationWithCounter = Operation with Counter; class AutoStepOperation extends $OperationWithCounter {   void operate([int step]) {     super.operate(step ?? super.next());   } } 

The mixin application of Counter to Operation create a new class, and that class appears in the superclass chain of AutoStepOperation.

If you do class X extends Y with I1, I2, I3 { ... } then you create four classes. If you just do class X extends Y implements I1, I2, I3 { ... } then you only create one class. Even if all of I1, I2 and I3 are completely empty abstract interfaces, using with to apply them is equivalent to:

class $X1 extends Y implements I1 { /* no members in I1 */ } class $X2 extends $X1 implements I2 { /* no members in I2 */ } class $X3 extends $X2 implements I3 { /* no members in I3 */ } class X extends $X3 { /* members of X */ } 

You wouldn't write that directly, so you shouldn't write it using with either

like image 182
lrn Avatar answered Sep 30 '22 11:09

lrn


Don't be afraid with mixin, it's here to help 🎉

💣 Spoiler : mixin is not related to Animation by any means 😂, its just another keyword like class

But mixin is similar to :

fastfood 🍔/ plugin 🧩/ an interface with already implemented methods & state, that is ready to be used without reimplementing those features everywhere we need them

When paired up with a StatefulWidget's State,TickerProviderStateMixin creates ticker that ticks with every frame which is need by every AnimationController . It also disposes ticker when stateful widget disposes. That's why we provide this as TickerProvider(vsync) in every AnimationController.

Similarly we use ListMixin to use obvious implementation of List so that we do not have to implement obvious stuffs in every List implementation like ElementList,NodeList,FileList,TouchList etc.

Now let's try to compare and contract extends, implements and mixin

extends (inheritance) => only one class can be inherited along with their public/protected members and behaviours.

implements (contract) => many classes can be implemented but we have to redefine every behaviour.

with(mixin) => Many classes can be mixed in and we can reuse the behaviour of them.

Now, how to use mixin :

Any class or abstract class can be used as mixin. But if we declare mixin, it cannot be extended like normal class or abstract class.

class A{} //Declaring class mixin B{} //Declaring mixin class C extends A{} // Valid ✅ class C implements A{} // Valid ✅ class C with A{} // Valid ✅ class C extends B{} // Invalid ❌ class C implements B{} // Valid ✅ 

But a mixin cannot use another mixin.

mixin C with B{} // Invalid ❌ 
like image 38
erluxman Avatar answered Sep 30 '22 11:09

erluxman