Loading classes dynamically in Dart

Issue

So, I looked into mirror and they might be an option, but given their async nature they might be really awkward to use or just not viable in the long run. Since they are currently not supported (just a play-thing) they are not really viable at this time anyway.

Question: Given a series of Strings, eg. [ "Foo", "Bar" ] a base class Application and Widget in library corelib; and a corresponding class for each of the strings FooWidget, BarWidget in library applibrary;, what’s currently the most elegant method to get Application to turn the strings into instances of the corresponding classes, that works with dart2js.

Equivalent PHP pseudo-example for clarity,

<?php # example

namespace corelib;

class Widget {
    function name() { 
        return \get_called_class(); 
    }
}

class Application {
    static function resolve($name, $library) { 
        $class = $library.'\\'.$name.'Widget'; 
        return new $class;
    }
}

namespace applibrary;

class FooWidget extends \corelib\Widget {
    // ...
}

class BarWidget extends \corelib\Widget {
    // ...
}

$foowidget = \corelib\Application::resolve('Foo', 'applibrary');
$barwidget = \corelib\Application::resolve('Bar', 'applibrary');

echo "{$foowidget->name()} <br> {$barwidget->name()}";

Output

applibrary\FooWidget 
applibrary\BarWidget

Solution

If you can validate the list of strings, then the best way for the moment (until mirror support in dart2js becomes better baked), is likely an if statement.

// toy implementation
Widget getWidget(name) {
  switch (name) {
     case "Foo": return new FooWidget();
     case "Bar": return new FooWidget();
     default: // handle error
  } 
} 

// elsewhere:
var fooWidget = getWidget("Foo");
var barWidget = getWidget("Bar");

The list of xyzWidget classes will be a finite list (as you can’t dynamically link in code at runtime anyway).

Of course, a more elegant implementation is to use mirrors (shown below, for reference, although it doesn’t currently fulfil the dar2js criteria)

Future<Widget> getWidget(library, name) {
  var completer = new Completer<Widget>();
  MirrorSystem ms = currentMirrorSystem();
  ClassMirror cm = ms.libraries[library].classes[name];
  // instantiate an instance of the class
  cm.newInstance(null,[]).then((instance) => completer.complete(instance));

  return completer.future;
}

// elsewhere:   
getWidget("applibrary","FooWidget").then((Widget widget) {
  // do something with widget
});

Answered By – Chris Buckett

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

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