How do I execute Dynamically (like Eval) in Dart? How do I execute Dynamically (like Eval) in Dart? dart dart

How do I execute Dynamically (like Eval) in Dart?


Ladislav Thon provided this answer (on the Dart forum),

I believe it's very safe to say that Dart will never have eval. But it will have other, more structured ways of dynamically generating code (code name mirror builders). There is nothing like that right now, though.

There are two ways of spawning an isolate: spawnFunction, which runs an existing function from the existing code in a new isolate, so nothing you are looking for, and spawnUri, which downloads code from given URI and runs it in new isolate. That is essentially dynamic code loading -- but the dynamically loaded code is isolated from the existing code. It runs in a new isolate, so the only means of communicating with it is via message passing (through ports).

Thank you Ladislav...


You can run a string as Dart code by first constructing a data URI from it and then passing it into Isolate.spawnUri.

import 'dart:isolate';void main() async {  final uri = Uri.dataFromString(    '''    void main() {      print("Hellooooooo from the other side!");    }    ''',    mimeType: 'application/dart',  );  await Isolate.spawnUri(uri, [], null);}

Note that you can only do this in JIT mode, which means that the only place you might benefit from it is Dart VM command line apps / package:build scripts. It will not work in Flutter release builds.

To get a result back from it, you can use ports:

import 'dart:isolate';void main() async {  final name = 'Eval Knievel';  final uri = Uri.dataFromString(    '''    import "dart:isolate";    void main(_, SendPort port) {      port.send("Nice to meet you, $name!");    }    ''',    mimeType: 'application/dart',  );  final port = ReceivePort();  await Isolate.spawnUri(uri, [], port.sendPort);  final String response = await port.first;      print(response);}

I wrote about it on my blog.


Eval(), in Ruby at least, can execute anything from a single statement (like an assignment) to complete involved programs. There is a substantial time penalty for executing many small snippets over most any other form of execution that is possible.

Looking at the problem closer, there are at least three different functions that were at the base of the various schemes where eval might be used. Dart handles at least 2 of these in at least minimal ways.

Dart does not, nor does it look like there is any plan to support "general" script execution.

However, the NoSuchMethod method can be used to effectively implement the dynamic "injection" of variables into your local class environment. It replaces an eval() with a string that would look like this: eval( "String text = 'your first name here';" );

The second function that Dart readily supports now is the invocation of a method, that would look like this: eval( "Map map = SomeClass.some_method()" );

After messing about with this it finally dawned on me that a single simple class can be used to store the information needed to invoke a method, for a class, as a string which seems to have general utility. I can replace a big maintenance prone switch statement that might otherwise be necessary to invoke a series of methods. In Ruby this was almost trivial, however in Dart there are some fairly less than intuitive calls so I wanted to get this "trick" in one place, which fits will with doing ordering and filtering on the strings such as you may need.

Here's the code to "accumulate" as many classes (a whole library?) into a map using reflection such that the class.methodName() can be called with nothing more than a key (as a string).

Note: I used a few "helper methods" to do Map & List functions, you will probably want to replace them with straight Dart. However this code is used and tested only using the functions..

Here's the code:

//The used "Helpers" here..MAP_add(var map, var key, var value){ if(key != null){map[key] = value;}return(map);}Object MAP_fetch(var map, var key, [var dflt = null]) {var value = map[key];if (value==null) {value = dflt;}return( value );}class ClassMethodMapper {  Map    _helperMirrorsMap, _methodMap;  void accum_class_map(Object myClass){    InstanceMirror helperMirror = reflect(myClass);    List methodsAr  = helperMirror.type.methods.values;    String classNm  = myClass.toString().split("'")[1]; ///#FRAGILE          MAP_add(_helperMirrorsMap, classNm, helperMirror);    methodsAr.forEach(( method) {      String key = method.simpleName;      if (key.charCodeAt(0) != 95) { //Ignore private methods        MAP_add(_methodMap, "${classNm}.${key}()", method);      }    });  }  Map invoker( String methodNm ) {    var method = MAP_fetch(_methodMap, methodNm, null);    if (method != null) {               String classNm = methodNm.split('.')[0];              InstanceMirror helperMirror = MAP_fetch(_helperMirrorsMap, classNm);      helperMirror.invoke(method.simpleName, []);    }  }  ClassMethodMapper() {    _methodMap         = {};    _helperMirrorsMap  = {};  }}//END_OF_CLASS( ClassMethodMapper );============main() {   ClassMethodMapper cMM = new ClassMethodMapper();   cMM.accum_class_map(MyFirstExampleClass);   cMM.accum_class_map(MySecondExampleClass);   //Now you're ready to execute any method (not private as per a special line of code above)   //by simply doing this:   cMM.invoker( MyFirstExampleClass.my_example_method() );}