Tuesday, February 7, 2012

Passing Classes by Reference in Dart

‹prev | My Chain | next›

Having addressed a minor Dart-to-Javascript mystery, I am ready to dive back into my rudimentary MVC framework. Up tonight: collections.

I can factor just about everything that I previously had in my ComicsCollection class out into a base class. This leaves behind something like:
#library('Collection class to describe my comic book collection');

#import('HipsterCollection.dart');
#import('Models.ComicBook.dart');

class Comics extends HipsterCollection {
  Comics() {
    url = '/comics';
    model = ComicBook;

    on = new CollectionEvents();
    models = [];
  }
}
The on and models object properties ought to get pushed into the base class as well. I will worry about that another time. For now I would like to make sure that the url and model properties are working.

The url property is pretty straight-forward. I am only using it to fetch() a collection of models. There is nothing too fancy there:
#library('Base class for Collections');

#import('dart:html');
#import('dart:htmlimpl');
#import('dart:json');

class HipsterCollection {
  var url, model, models, on;

  //...

  fetch() {
    var req = new XMLHttpRequest();

    req.on.load.add(_handleOnLoad);
    req.open('get', url, true);
    req.send();
  }
}
What is fancy (well, relatively speaking) is the instantiation of models for the collection. Since I am setting the model = ComicBook in my collection class, I would like to create the models something like this:
class HipsterCollection {
  var url, model, models, on;
  // ....

  _handleOnLoad(event) {
    var request = event.target
      , list = JSON.parse(request.responseText);

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

    on.load.dispatch(new Event('load'));
  }
}
The only problem is that Dart does not care for the model = ComicBook assignment:
Internal error: 'http://localhost:3000/scripts/Collections.Comics.dart': Error: line 9 pos 13: Unresolved identifier 'Library:'http://localhost:3000/scripts/Models.ComicBook.dart' Class: ComicBook'
    model = ComicBook;
            ^
I spend a bit of time rooting around for ways to create classes from strings and the like in Dart, but come up empty. I also try static class methods:
class HipsterModel {
  static constructor() {
    // construct things
  }
  //...
}
But, when I try to assign that to my model attribute:
class Comics extends HipsterCollection {
  Comics() {
    url = '/comics';
    model = ComicBook.constructor;
    //...
  }
}
I am greeted with another error:
Internal error: 'http://localhost:3000/scripts/Collections.Comics.dart': Error: line 9 pos 23: unknown static field 'constructor'
    model = ComicBook.constructor;
                      ^
Eventually, I settle on a constructor function:
class Comics extends HipsterCollection {
  Comics() {
    url = '/comics';
    model = (attrs) => new ComicBook(attrs);
    // ...
  }
}
I may not be able to assign class names or static methods, but I can assign anonymous functions. In the HipsterCollection base class, I can then create new models like this:
class HipsterCollection {
  var url, model, models, on;
  // ....

  _handleOnLoad(event) {
    var request = event.target
      , list = JSON.parse(request.responseText);

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

    on.load.dispatch(new Event('load'));
  }
}
That is somewhat unsatisfying because my base class looks prettier than my sub-class. If I stick with this implementation, I will probably have to rename the model attribute to something like model_constructor. More bothersome than a long attribute name how verbose it has to be when I only want to describe that the model being collected is a ComicBook.


Day #289

3 comments:

  1. Wouldn't it be much easier to use generics here: https://gist.github.com/1778137, or I missed something here?

    ReplyDelete
    Replies
    1. Interesting. That very well may be the "Dart way" to accomplish what I want. I had only thought of generics as a way to constrain values and definitely had not realized that you can use them to create new instances of the thing. That's a nice little trick.

      I will definitely play around with this. I wonder if T would be ComicBook if I sub-classed HipsterCollection as: `class Comics<ComicBook> extends HipsterCollection`. If it does, then problem solved.

      Regardless, I am excited about this application of generics. Thanks for pointing it out!

      Delete
    2. I tried this (http://japhr.blogspot.com/2012/02/generic-constructors-in-dart.html), but it seems constructing from generic type information is not currently allowed :-(

      Delete