Friday, February 10, 2012

Generic Constructors in Dart

‹prev | My Chain | next›

I have my Dart-based MVC framework in a good place. Well, at least a more or less working place. Now is a good time to do a bit of refactoring starting with how I build models in my collections.

Currently, to tell the collection how to create models, I pass it an anonymous function:
class Comics extends HipsterCollection {
  Comics() {
    url = '/comics';
    model = (attrs) => new ComicBook(attrs);

    on = new CollectionEvents();
    models = [];
  }
}
I was not terribly happy about that solution, but it worked.

Andreas Köberle suggested trying to use generics, about which I know virtually nothing. From the Wikipedia article, they are "algorithms are written in terms of to-be-specified-later types". Ah, that explains it. In Javascript and Ruby, I am used to passing references to classes all the time—something of an informal generics programming. In Dart, it seems, that things need to be a bit more formal.

Back in my HipsterCollection base-class, I can define a generic with the type parameter inside angle brackets:
class HipsterCollection<M> {
 // ...
}
Simply reading that, I can look at it as saying that HipsterCollections are built from things of type "M". If I create my HipsterCollection with an explicit type of ComicBook, then perhaps I can create models with the following:
new M(attrs)
That would be nice.

So I replace my model maker function with a new Generic:
class HipsterCollection {
  // ...
  _handleOnLoad(event) {
    var request = event.target
      , list = JSON.parse(request.responseText);

    list.forEach((attrs) {
      // models.add(model(attrs));
      models.add(new M(attrs);)
    });

    on.load.dispatch(new CollectionEvent('load', this));
  // ...
}
Unfortunately, that blows up:
Internal error: 'http://localhost:3000/scripts/HipsterCollection.dart': Error: line 58 pos 18: type parameter 'M' cannot be instantiated
      models.add(new M(attrs);)
                 ^
Looking through the spec, it seems that I am running afoul of: "A type parameter cannot be used to name a constructor in an instance creation expression."

Dang. It seems as though generics are quite a useful as I had hoped. If I run in checked mode, I can do things like extending the generic to enforce that the type is a model:
class HipsterCollection<M extends HipsterModel> {
  // ...
}
But, coming from the wild west of Ruby and Javascript land, this feel like unnecessary ceremony. Ah well, here's hoping that someday the Dart-lords remove that restriction. For now, I will stick with my model-maker function.


Day #292

No comments:

Post a Comment