Sunday, August 4, 2013

Getting Started with Dart Mixins and “IterableMixin”


I was pretty happy to discover the IterableBase and ListBase classes yesterday. They make creating iterable and list-like objects in Dart trivial.

Before another sure-to-be-amazing #pairwithme session tonight, I am going to do a quick follow-up to last night's effort. While working with the two “Base” classes, I noted the existence of the IterableMixin class as well. Aside from some quick play when the feature was first added, I have not really messed with the official mixin solution for Dart. This seems like a good chance.

Instead of extending the IterableBase class as I did last night:
class ComicsCollection extends IterableBase {
  // ...
  List models = [];
  Iterator get iterator => models.iterator;
  // ...
}
I would like to mixin the same functionality. Based on the documentation, both the IterableBase base class and the IterableMixin mixin class only need one thing to work (and it is it the same thing for both): the iterator getter.

The language specification seems to want mixins to be typedef'd. The introduction article on mixins indicates that using the with keywords in class definitions should work (actually this is also mentioned in the spec, but is listed as “not yet supported”). I opt to try the class definition first:
class ComicsCollection with IterableMixin {
  // ...
  List models = [];
  Iterator get iterator => models.iterator;
  // ...
}
That fails when I give it a try:
Internal error: 'file:///public/scripts/comics.dart': Error: line 33 pos 24: { expected
class ComicsCollection with IterableMixin {
                       ^ 
I had wondered about that because the article only does mixins when also subclassing another class. The specification too, seems to indicate that mixin declarations are only allowed when subclassing. I am not sure of the rational behind that. In Ruby, it is possible—encouraged even—to mixin with plain old ordinary classes. Mixins in Dart are relatively new so I am not going to be too fussed. Instead, I try subclassing.

Since I do not really need to subclass anything in this case, I subclass Object, which is the baseclass of everything in Dart:
class ComicsCollection extends Object with IterableMixin {
  // ...
  List models;
  Iterator get iterator => models.iterator;
  // ...
}
That does the trick. My code compiles and my tests pass. If I remove the iterator getter, then tests fail and I get exceptions:
Uncaught Error: Class 'ComicsCollection' has no instance getter 'iterator'.

NoSuchMethodError : method not found: 'iterator'
Receiver: Instance of 'ComicsCollection'
So the IterableMixin is actually working as desired.

Coming from Ruby-land, I am pretty excited about mixins. They are wonderful for adding a bunch of behaviors to a class, while still allowing the class to subclass a separate class. I suppose that use-case is the reason that Dart currently requires a class to be extending a superclass in order to use a mixin. In all honesty, I have not used many Ruby mixins aside from Enumerable. Dart already has this covered for the no-superclass case (with IterableBase) and the superclass case (with ItererableMixin).

In other words, I am hard-pressed to worry too much about Dart's no-baseclass mixin strategy at this point. My primary use-case is covered. Even if I find another use-case before mixins evolve, it is not too horrible to extend Object. The bottom line is: mixins yay!


Day #833

1 comment:

  1. As I've explained on several occasions, the "with" clause is in fact part of the "extends" clause. Class declaration doesn't look like "class C (extends SC) (with M1, M2) (implements I1, I2) {...}", it looks like "class C (extends (SC with M1, M2)) (implements I1, I2) {...}". And it actually conforms to the semantics: if I have a "class C extends SC with M1, M2", then C extends the class SC+M1+M2, which in turn extends the class SC+M1, which finally extends the class SC. This is how mixins in Dart work.

    ReplyDelete