Dart Fundamentals-Mixins

Dart mixins are a wonderful language feature that can help you reuse code across classes. In this article we will explore Dart mixins with a working example. In our example we will build several different super heroes and they'll get their super powers according to what mixins they are given. Since our super powers will be implemented in the mixin we won't have to re-code it for each super heroe. This is the power of mixins.

Our Definition of a Hero

To allow all of our heroes to share a common interface, we'll create an abstract class that each super heroe will extend. This in of itself has nothing to do with mixins but you'll often see mixins employed alongside standard OOP designs including inheritance.

abstract class Hero {  
  final String _name;
  Hero(this._name);
  String helpPersonInNeed() => '$_name is helping a person in need!';
  Point move();
  int attack();
}

We marked this class as abstract since we don't want it to be instantiated directly. And we gave it a few things that all heroes should have - a name, helping someone in need, and some basic abilities to move and attack. Next, let's look at our actual super heroes...

Our Super Heroes

For our example we will create two super heroes: The Incredible Hulk and Iron Man.

Here is our Hulk:

class Hulk extends Hero {
  Hulk() : super("Hulk");

  @override
  Point move() {
    return null; //TODO implement
  }

  @override
  int attack() {
    return null; //TODO implement
  }
}

And here is Iron Man:

class IronMan extends Hero {
  IronMan() : super("Iron Man");

  @override
  Point move() {
    return null; //TODO implement
  }

  @override
  int attack() {
    return null; //TODO implement
  }
}

As you can see we need to implement how each hero moves and how they attack. Hulk and Iron Man move and attack very differently. Hulk likes to jump and smash things whereas Iron Man likes to fly and shoot lasers (technically repulsors if you are geeky enough to know that). But super heroe powers like jumping and flying are traits shared by other super heroes. For example Spiderman is a jumper and Superman flys as well. So it makes sense to break out the implementation of these powers. We'll do so next by creating several mixins.

Mixins

In the last section we said we were going to break out super powers into mixins but before we get to doing that, let's talk about mixins in general. Here are a few things to know:

  • Mixins typically begin with the 'mixin' keyword but they don't have to. You can mixin a normal class but the general recommendation is against this.
  • Mixins cannot have constructors. This rule also applies to any class you try to use as a mixin.
  • To add a mixin to a class, use the 'with' keyword.
  • You can constrain what classes can use a mixin by adding the 'on' keyword to the mixin itself. Following the 'on' keyword should be a list of classes that can use the mixin.

If you are interested in the actual specification for mixins in Dart, here you go: Dart 2.2 Language Specifications

Now, on to our super heroe mixins!

Jumping

Some heroes can jump, let's define a simple mixin that defines how heroes jump.

mixin jumping {
  Point jump() {
    return Point(5, 5);
  }
}

Flying

Some heroes can fly, here is another mixin that defines flight. As you can see, flying is faster than jumping!

mixin flying {
  Point fly() {
    return Point(10, 10);
  }
}

Super Healing

Some heroes have the ability to heal quickly. This mixin defines that trait by returning a health of 100%.

mixin superHealing {  
  int heal() {
    return 100;
  }
}

Super Human Strength

For heroes that can bench press a car, strength is their forte. This mixin holds our implementation of strength.

mixin superHumanStrength {
  int smash() {
    return 100;
  }
  int punch() {
    return 60;
  }
}

Technology

Having a strong grasp on technology can help heroes get out of a tight spot and win the day. This mixin is for those heroes.

mixin technology {
  int lasers() {
    return 60;
  }

  double compute() {
    var result = pi;
    print('Computing pi... computation complete: $result');
    return result;
  }
}

With some nifty super power mixins defined, let's go back to our heroes and grant them their powers.

Hulk Smash!

Hulk will get the jumping, superHealing, and superHumanStrength powers:

class Hulk extends Hero with jumping, superHealing, superHumanStrength {
  Hulk() : super("Hulk");

  @override
  Point move() {
    var p = jump();
    print('$_name has jumped to position $p');
    return p;
  }

  @override
  int attack() {
    var damage = smash();
    print('$_name has smashed resulting in damage to opponent of $damage');
    return damage;
  }
}

Notice how we have used Hulk's jumping mixin to define his favorite way to move. In addition, Hulk loves to smash things so his attack will use the superHumanStrength implementation of smash.

I am Iron Man!

Iron Man will receive the flying and technology powers:

class IronMan extends Hero with flying, technology {
  IronMan() : super("Iron Man");

  @override
  Point move() {
    var p = fly();
    print('$_name has flown to position $p');
    return p;
  }

  @override
  int attack() {
    var damage = lasers();
    print('$_name has fired lasers resulting in damage to opponent of $damage');
    return null;
  }
}

Iron Man moves about by the fly() method we get from the flying mixin and his favorite attack is by way of laser beam that comes from the lasers() method of the technology mixin.

Put our Heroes to Work

Now that we have granted our super heroes their powers let's put them to work. This will be a simple exercise where we create a small Dart console app to instantiate the heroes and let them do their thing.

main(List<String> arguments) {

  var hulk = Hulk();
  print(hulk.helpPersonInNeed());
  hulk.move(); 
  hulk.attack();

  var ironMan = IronMan();
  print(ironMan.helpPersonInNeed());
  ironMan.move();
  ironMan.attack();
  ironMan.compute();
}

Running the application yields some output to the console:

Hulk is helping a person in need!
Hulk has jumped to position Point(5, 5)
Hulk has smashed resulting in damage to opponent of 100
Iron Man is helping a person in need!
Iron Man has flown to position Point(10, 10)
Iron Man has fired lasers resulting in damage to opponent of 60
Computing pi... computation complete: 3.141592653589793

Summary

Mixins are a great way to add specific features to classes and promote code reuse. I hope you have enjoyed this article and let me know if you would like to see more articles in the future on specific Dart topics.

-Joe

1 thought on “Dart Fundamentals-Mixins”

Leave a Reply

Your email address will not be published. Required fields are marked *