Jan Vladimir Mostert Jan Vladimir Mostert - 26 days ago 12
Dart Question

Instantiating a generic class in dart

I've looked at the examples on stackoverflow using typedef, but it looks like it's mostly used for callbacks, so not sure if it's relevant for what I'm working on.
I'm implementing a class using generics that does RPC ...



abstract class Message {

int created = new DateTime.now().millisecondsSinceEpoch;
Map map = new Map();

Map toJson();
void fromJson(String json){
map = JSON.decode(json);
this.created = map["created"];
}

String toString() {
return JSON.encode(this);
}

Message(){
map["created"] = created;
}

}


___Request and ___Response both extends Message:

import 'Message.dart';

class TestResponse extends Message {

String test;
String message;

Map toJson() {
map["test"] = this.test;
return map;
}

fromJson(String json) {
super.fromJson(json);
this.test = map["test"];
this.message = map["message"];
}

}


Now when I try to do a generic RPC class that hides all the boilerplate of sending and receiving messages, I need to create a new instance of the response class to send it back.
(I would have preferred to do RPC.submit, but that gives me an error saying static Static members cannot reference type parameters, so my other option here is to maybe abuse the constructor syntax, eg RPC.submit(json, uri).getResponse() ...)

import 'package:http/browser_client.dart';
import 'Message.dart';

class RPC<REQ extends Message, RES extends Message> {

RES submit(REQ req, String uri){
var client = new BrowserClient();
var url = "http://localhost:9090/application-api" + uri;
RES res = new RES(); // <----- can't do this
client.post(url, body: req.toString()).then((response){
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
res.fromJson(response.body);

});
return res;
}

}


In my submit method, I can obviously pass in an instance of "RES res" and just use that, but I was hoping that it can be done inside the generic RPC without too much extra boilerplate, is that somehow possible in dart?

Answer

Seems related to http://dartbug.com/10667

What I did in a similar situation was to create a static map which maps types to closurized constructors. I initialize the map with the message types and a closure for each which create a new instance of that type. Then I look up the closure using the type argument and call the returned closure to get a new instance.

var factories = {
  'A': () => new A(),
  'B': () => new B(),
  'C': () => new C(),
};

...

var a = factories['A']();

You can integrate the factory into the class

class A {
  static A createNew() => new A();
}

var factories = {
  'A': A.createNew,
  'B': B.createNew,
  'C': C.createNew,
};
...
var a = factories['A']();
Comments