Is there a way to Dynamically execute blocks of script (from text)

730 views
Skip to first unread message

SwarmShepherd

unread,
Nov 27, 2012, 7:31:43 AM11/27/12
to mi...@dartlang.org

Hi all,

Since getting started in Dart I've been watching for a way to execute Dart (Text) Source (that the same program may well be generating dynamically) as Code.  Like the infamous "eval()"   function.

Recently I have caught a few hints that the communication port between Isolates support some sort of "Spawn" that seems like it could allow this "trick".    In Ruby there is also the possibility to load a module dynamically as a language feature, perhaps there is some way to do this in Dart?

Any clues or a simple example will be greatly appreciated.   

Thanks in advance!

_swarmii

(and YES, this is something of a "how to" question,  and I will ask/answer it on StackOverflow if I get an answer I can understand and use here.)

Ladislav Thon

unread,
Nov 27, 2012, 7:51:56 AM11/27/12
to mi...@dartlang.org
Since getting started in Dart I've been watching for a way to execute Dart (Text) Source (that the same program may well be generating dynamically) as Code.  Like the infamous "eval()"   function.

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.
 
Recently I have caught a few hints that the communication port between Isolates support some sort of "Spawn" that seems like it could allow this "trick".

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).

LT

SwarmShepherd

unread,
Nov 27, 2012, 3:45:43 PM11/27/12
to mi...@dartlang.org

Tom Yeh

unread,
Jan 2, 2013, 9:54:06 PM1/2/13
to mi...@dartlang.org
Allow me to raise the bar. Dynamic evaluation is important at the server side. For example, without it, it is not possible to implement map-reduce functions in Dart for CouchDB (because of View Server's protocol). Furthermore, we can't implement a solution that compiles a template into Dart code at run time (as we compile JSP to Java).

Bob Nystrom

unread,
Jan 3, 2013, 1:34:04 PM1/3/13
to General Dart Discussion


On Wed, Jan 2, 2013 at 6:54 PM, Tom Yeh <tom....@gmail.com> wrote:
Allow me to raise the bar. Dynamic evaluation is important at the server side.

I'd like to make a distinction here (maybe you already have this distinction in mind, but I'll just spell it out for my own benefit):

1. The ability to execute a dynamically generated "chunk" (string, AST, whatever) of Dart code at runtime.
2. The ability to do so in the context/scope of an already running Dart program.

I think we absolutely should have #1. Without that, plug-ins, "scriptability", extensibility, etc. are all a nightmare. I think we probably won't have #2 for generally good reasons. It's insecure and it takes a bunch of compiler optimizations off the table.

Is #1 all that you had in mind here?

- bob


Ladislav Thon

unread,
Jan 3, 2013, 2:18:50 PM1/3/13
to mi...@dartlang.org
1. The ability to execute a dynamically generated "chunk" (string, AST, whatever) of Dart code at runtime.
2. The ability to do so in the context/scope of an already running Dart program.

I think we absolutely should have #1. Without that, plug-ins, "scriptability", extensibility, etc. are all a nightmare. I think we probably won't have #2 for generally good reasons. It's insecure and it takes a bunch of compiler optimizations off the table.

Is #1 all that you had in mind here?

I'm not the OP, but...

As long as you can affect the scope of the generated code -- setting some context before executing and getting some results after --, the first option is all I personally want. Also, if the set of types that could be passed to/from the code had to be restricted to the "basic" types (you know, the same types that can be passed across isolates), I think I would be able to live with that -- but I'd prefer if I didn't have to.

LT

Alex Tatumizer

unread,
Jan 3, 2013, 2:25:43 PM1/3/13
to mi...@dartlang.org
I think the difference between 1) and 2) is more or less the same as difference between javascript eval() and Function() constructor.
If we have an equivalent of Function() constructor (where you can pass the source code as string, evaluated in global scope), this would cover most practical needs IMO.

George Koller

unread,
Jan 3, 2013, 4:57:41 PM1/3/13
to mi...@dartlang.org
Hey guys,

Haven't posting much of late but I've been busy on my project.  Have now pretty much translated all of my Ruby project now into Dart. Ruby about 5,000 lines, Dart some 6,200 lines and maybe 600 more coming to finish.   Generally I'd say I've had maybe 4-5-6 things just really seem to "let me down",  and of these issues the inability to execute even a a single small chunk of script (like just an assignment to a new variable) is my #1 'gripe'.  Dart can gets me right to the point where I could be implementing a low maintenance/self adjusting design but without being able to make "dynamic assignments" I come up short in several ways.  Have tricked the system into working somewhat with the noSuchMethod method but overall this is not as nice a solution - for example it requires a Map fetch for each use of the variable (which becomes a method call) rather than allowing it to be shoved into the environment.   It has been really a irritating step backwards for me to have to write "Invoking methods" with big ugly case statements (virtually banned from my Ruby work for years) because these will 'break' with the slightest change to a method name.  Turns my positive design feature into a poor design.  My otherwise Dynamic / self-adjusting design comes up short while in Ruby it simply executed whatever methods it found (no muss, no fuss).   

So #1 is clearly my #1 gripe on Dart after several months of this work.  No #2 above is tricky because, in my case, I want to load the result of executing a block of code into "the environment of the calling class".  Not a computer scientist and unsure how to suggest this, and perhaps this is doable with the 'Expando' feature, not sure, but perhaps a dynamic assignment statement could be allowed?  I do other-things in other places and it is a centerpiece of one of my best pieces of code every imho that I could execute whole blocks of code, but this would cover some 50% of my use and get me over the immediate dilemma.   

Overall not so unhappy, excited even, but this lack of being able to fetch the response from a method dynamically is cramping my style!  Oddly enough, I have shared this with some folks that know Dart better than I do and they have not, I suspect, caught on to the "trick" that we Rubyists have known and used for years.  Not, honestly, that I know many Ruby-ists, but the top notch ones I knew consider switch statements really bad style...

Also, with the mediocre dynamic solution I did come up with, the best I could do back 2 months ago or so, came up short in that I needed to assign the results of a method invocation to a global, then read the global because fetching the result of the method did not seem possible.  I also consider this a major missing feature - but it seems likely this hole has been plugged?

Again, however, I'm not unhappy overall, as an old desktop applications guy I am excited as heck to be able to work in a single language.  I'm hoping to not remain a team of one, but I think it is "revolutionary" in Web evolution that the same code from a single "real" language will run in the Browser and on the Server!  That's major, and this other stuff, well, will take time.

Now that I have pretty much duplicated the functionality of the Ruby Project I am allowing myself to think about all the powerful things that I can implement into my own set of Graphical (Control Statistical, generally) charts and the ideas keep coming!  

BTW, one side-note, I have rather reverse-engineered the Ruby "Prawn" (pdf) Gem into a rather cute little Dart Library (of 2private classes and one public).  It uses HTML5 canvas to do into the screen work that this package did into a displayed PDF file.  All based on some 14 canvas methods.  Its satisfies all my immediate needs with minimal overhead for my project (including some really basic text grid features).  No idea whatsoever if this library would have value to other Dart Programmers.

Also at some point, before too long, I'd love to have a short chat with a Google guy to see what might make sense in the future for my project, I'm at an interesting design decision point, and have pretty much zero experience with hosting Web applications.

Happy New Year to all!

_swarmii


--
Consider asking HOWTO questions at Stack Overflow: http://stackoverflow.com/tags/dart
 
 

Alex Tatumizer

unread,
Jan 3, 2013, 5:17:51 PM1/3/13
to mi...@dartlang.org

>Have tricked the system into working somewhat with the noSuchMethod method but overall this is not as nice a solution - for example it requires a Map >fetch for each use of the variable (which becomes a method call) rather than allowing it to be shoved into the environment. 

Could you describe a use case in greater detail?( I'm just curious about scenario where performance is so critical that extra lookup in a map can become a showstopper)

George Koller

unread,
Jan 3, 2013, 7:48:13 PM1/3/13
to mi...@dartlang.org
Tatumizer,

OK, this will be general.  Again and again in programming I've learned to separate the 'Data' from the 'Rules'.  First program and 35 years later.   As we're using OO, what unit makes the most (or any) sense?  The class is what I have resolved on - and multiple classes for multiple Topics if things needed to be divided up so that would become a library.  So, how to "poke" this living breathing class for data?  Well, the most basic thing for us to do is call a method by name  and now we can retrieve data in a nice self describing Map and go to town on it....

Here's a literal example (it might be clear how its used):
 
  Map page_title_gc02() { 
return( GlRtrnMap = {'with': 'studyTitle', 'fireAr': ['Page.title()'],    'XLoc':  20, 'YLoc':  725, 'Width':  540, 'Text':  _title,    'FontSize': 10, 'UnderlineYOS':  -16,   'UnderlineXOS':  2, 'UnderlineWidth':  508, 'UnderlineThick':  4, 'UnderlineColor':  BROWN_SANDY  });
  }

But how to USE the information in the Map? In Ruby I simply "poked it" into the (dynamic) environment of the calling class (as class variables) - and I'd have what I needed to proceed.  
Dart 
   1.  Calls the methods out of the expected order - no problem, 'fixed' that. (The list return doesn't keep the order of the methods in the Class).
2.  There is no way to fetch the data (that I could find) so then I'm messing about with a Global (a no no in my book).
3.  Then I can poke the data into the environment and use it because there's no way to do anything like that in the same thread yet.
4.  NoSuchMethod puts warnings all over the place where the calls are made - complaining that the class doesn't have such a method, no big deal, no "show-stopper" but I feel more like I'm making a design compromise than doing what I thought of in Ruby as well structured code.
Also, as mentioned, if I USE the variable in a loop maybe 20 times, then the bloody thing is accessed 20 times in that loop or I have to make another statement to get it assigned to a method variable.  Not a BIG thing but this shows up Again and Again and again making for 100's of extra lines of code...

All in all I used this "Trick" no less than 4 times in my project and after spending days to arrive at a feeble imitation of what I think is good code, I just went to using these maintenance heavy, code tangling (breaks the DRY rule - Don't Repeat Yourself) performance compromising, ugly switch statements that I thought I had seen the last of.

I respect the need for security, and I'm not (I'm repeating myself) a computer scientist but I felt much better about this aspect of this project in my Ruby code than I can about what I'm doing in the Dart Project....   not a show stopper, but I long for the elegance and simplicity of Ruby in this particular aspect of the project.

There are several planned future extensions to my project that would make heavy use of "firing" script files that are classes (in Ruby actually modules).  I came up with a "WhiteBoard" concept for these scripts to "leave information" which I am thinking can be done with Isolates, and likely for the better in the long run.  Its simpler case of using Classes for storing data that seems to get tangled in yellow "under construction" tape so far...

Did I answer your question?'

Sincerely,

_swarmii


On Thu, Jan 3, 2013 at 4:17 PM, Alex Tatumizer <tatu...@gmail.com> wrote:

>Have tricked the system into working somewhat with the noSuchMethod method but overall this is not as nice a solution - for example it requires a Map >fetch for each use of the variable (which becomes a method call) rather than allowing it to be shoved into the environment. 

Could you describe a use case in greater detail?( I'm just curious about scenario where performance is so critical that extra lookup in a map can become a showstopper)

Bob Nystrom

unread,
Jan 3, 2013, 9:08:01 PM1/3/13
to General Dart Discussion
On Thu, Jan 3, 2013 at 4:48 PM, George Koller <gmko...@gmail.com> wrote:
OK, this will be general.  Again and again in programming I've learned to separate the 'Data' from the 'Rules'.  First program and 35 years later.   As we're using OO, what unit makes the most (or any) sense?  The class is what I have resolved on - and multiple classes for multiple Topics if things needed to be divided up so that would become a library.

This sounds a lot to me like DCI.
 
 So, how to "poke" this living breathing class for data?  Well, the most basic thing for us to do is call a method by name  and now we can retrieve data in a nice self describing Map and go to town on it....

I didn't follow this. So you have an instance of some class, but the class itself doesn't define what kind of data it holds? Instead, it just has a method that can return a map of that data upon request? What value does the class provide then?
 

Here's a literal example (it might be clear how its used):
 
  Map page_title_gc02() { 
return( GlRtrnMap = {'with': 'studyTitle', 'fireAr': ['Page.title()'],    'XLoc':  20, 'YLoc':  725, 'Width':  540, 'Text':  _title,    'FontSize': 10, 'UnderlineYOS':  -16,   'UnderlineXOS':  2, 'UnderlineWidth':  508, 'UnderlineThick':  4, 'UnderlineColor':  BROWN_SANDY  });
  }

But how to USE the information in the Map? In Ruby I simply "poked it" into the (dynamic) environment of the calling class (as class variables) - and I'd have what I needed to proceed.  
Dart 
   1.  Calls the methods out of the expected order - no problem, 'fixed' that. (The list return doesn't keep the order of the methods in the Class).

Can you explain this a bit more? List literals should evaluate their element expressions in order as far as I know. I think map literals do too, but I'm not positive.
 
2.  There is no way to fetch the data (that I could find) so then I'm messing about with a Global (a no no in my book).

In general, you can use mirrors to access the state that an object stores. But I'm not sure if that would help you here.
 
3.  Then I can poke the data into the environment and use it because there's no way to do anything like that in the same thread yet.
4.  NoSuchMethod puts warnings all over the place where the calls are made - complaining that the class doesn't have such a method, no big deal, no "show-stopper" but I feel more like I'm making a design compromise than doing what I thought of in Ruby as well structured code.

Hmm, I thought the editor was supposed to disable those warnings if it sees that the class implements noSuchMethod. Want to see if there's a bug for that and file one if not?
 
Also, as mentioned, if I USE the variable in a loop maybe 20 times, then the bloody thing is accessed 20 times in that loop or I have to make another statement to get it assigned to a method variable.  Not a BIG thing but this shows up Again and Again and again making for 100's of extra lines of code...

All in all I used this "Trick" no less than 4 times in my project and after spending days to arrive at a feeble imitation of what I think is good code, I just went to using these maintenance heavy, code tangling (breaks the DRY rule - Don't Repeat Yourself) performance compromising, ugly switch statements that I thought I had seen the last of.

I respect the need for security, and I'm not (I'm repeating myself) a computer scientist but I felt much better about this aspect of this project in my Ruby code than I can about what I'm doing in the Dart Project....   not a show stopper, but I long for the elegance and simplicity of Ruby in this particular aspect of the project.

There are a bunch of things that are easy and idiomatic in Ruby that don't translate very well to Dart (and vice versa). I find it usually works better to have a "When In Rome" approach and solve things in the way that's natural for the host language. It makes porting harder but I usually like the end result more.

I'd suggest something concrete here, but I don't have a good feel for what you're trying to accomplish. Is your code available somewhere we can look at it?
 

There are several planned future extensions to my project that would make heavy use of "firing" script files that are classes (in Ruby actually modules).  I came up with a "WhiteBoard" concept for these scripts to "leave information" which I am thinking can be done with Isolates, and likely for the better in the long run.

Sounds like you reinvented blackboards. :)

Cheers,

- bob

Tom Yeh

unread,
Jan 3, 2013, 9:17:04 PM1/3/13
to mi...@dartlang.org
#1 is good enough for what I am looking. However, does it allow to access the global context? Can we pass in instances of a custom class?

/ tom

Alex Tatumizer

unread,
Jan 3, 2013, 9:40:33 PM1/3/13
to mi...@dartlang.org
@_swarmii

Though I admit I don't have a full grasp of your problem, I got one thing: you want to add attributes to object, without NoSuchMethod.
Can I reformulate your problem as follows:
1) I have a map which looks like:
{'with': 'studyTitle', 'fireAr': ['Page.title()'],    'XLoc':  20, 'YLoc':  725, 'Width':  540, 'Text':  _title,    'FontSize': 10, 'UnderlineYOS':  -16,   'UnderlineXOS':  2, 'UnderlineWidth':  508, 'UnderlineThick':  4, 'UnderlineColor':  BROWN_SANDY  }

2) I have an object obj

3) I want to inject all attributes of said map into an object obj, so that I could write, e.g. "var x=obj.XLoc"

If this is ALL you need, you (AFAIK) can do it with Expando<Object>. But it's not clear to me what the object "obj" is for.  Why not use the above map just as a map? Why is it so important in your context
to inject every attribute of map into object itself? What does it have to do with dynamic execution? There are scenarios where you need to compile user-defined CODE (and need eval-like function to do that) but in your example, there's no code, just data. 



George Koller

unread,
Jan 3, 2013, 9:52:04 PM1/3/13
to mi...@dartlang.org

Hi again,

Just a thought on all this...in Ruby we could do the following:

evalStr = "@someClassVar = Hash.fetch 'someName' "
eval( evalStr )

Where  evalStr could really be just about any unit of text from a single statement, to an entire system of classes...

However, for much of my immediate purposes I would very much like to be able to make a simple single variable (dynamic) set something like this:

dynamicAssignment( evalStr );

where evalStr could be limited to 
   1.  a single statement
   2.  a "set" statement where the type is specified
   3.  the variable and its value is "poked" into the class calling it 

so we could do this:

dynamicVarAssignment( "String str = 'Foo' " );

or perhaps less eval-ish like:

dynamicVarAssignment( type:String,  varname:'str',  value:'Foo'  );

Would this avoid the security and performance issues mentioned above?

Dynamically assigned values could also be nicely distinguished from the pre-declared variables by the use of a prefix symbol like '@'.   

This would be very useful for what I'm trying to do in several places in my project, after all, no matter if its an array of hashes, or just whatever, it all just comes down to multiple assignment statements like this to somehow make the data available inside the class with minimum programming, and good performance.  So it could be all made as simple as:

meld( myMap );

and whatever is in that Map just becomes available within the class as class level variables - without further ado.  (Behind the scenes, perhaps,  it would be something like a noSuchMethod prequel untangling things - all nice and baked in.)   meld


Sincerely,

_swarmii 
 

SwarmShepherd

unread,
Jan 3, 2013, 10:29:48 PM1/3/13
to mi...@dartlang.org
Alex,

OK, here are more of the particulars, as I was just not sure if these details were of any significance.

So I have methods that define the data for a single study that look like this:

 
Map xChart_frame_gc24() {    //3 CHART, FRAME-X
   
return(GlRtrnMap = {'with': 'chartFrame', 'fireAr': ["Chart.frame()"],
     
'XLoc': _xLoc, 'YLoc': _yLocX, 'Height': _height, 'Width': _width, 'Radius': 8, 'Thick': 4, 'Color': BLACK_BASE
   
});
 
}


You will note that this method includes the name of the class and method it needs to USE the data to do something useful (as in present a chart frame).  These tend to look like this:
class Chart extends chartBase {

   
void frame() {
    p(">Page.frame()");
    pdf.line_width(studyFrameThick());
    pdf.stroke_color(studyFrameColor());
    pdf.rounded_rectangle([studyFrameXLoc(), studyFrameYLoc()], studyFrameWidth(), studyFrameHeight(), studyFrameRadius());
  }....

So, I guess this is DCI ?   In any case, I think it is just basic minimal good design to NOT repeat the algorithm(2nd) part over and over.  (The graphical calls to pdf are average maybe 5 canvas context 
statements BTW - so some good things seem to be coming together,  as far as I can tell.)

In Ruby I could "read" the first part, and using the info in the map "Send" to the data to the Proper Class (Chart) and proper method (frame()) to do the needed work on the data from the first part.

Note, in particular that the calls in the "rule" (2nd) part is just very "variable rich" (by design) - so extra "verbosity" can easily blow statements beyond 80 chars and make the code considerably less readable, not to mention ugly.

Well, just making function calls versus variables makes it slightly less readable, but accessing a map over and over, or making dozens of assignment statements would be massive.  A single "Study" has some 20 or more methods that define it.  And then there are already 7 studies with more to come - so anything I can do to make this code more concise, clearer, more consistent seems like time well spent.  (I recently learned from a trial that a single modest, and sparse study made over 5k canvas context level calls- this surprised me.)

Hope this all makes more sense now...

Sincerely,

_swarmii

Alex Tatumizer

unread,
Jan 3, 2013, 11:33:48 PM1/3/13
to mi...@dartlang.org
I think I got it, but in your case, all the names and types are known in advance, so you can just declare them in your class:
class Chart extends ChartBase {
   int XLoc;
   int YLoc;
   // etc.
   void frame() {
       pdf.rounded_rectangle(XLoc, YLoc /* ... etc */);
   }
}
To make it possible, you need just a generic function 
void inject(Object obj, Map map)

which can be implemented using reflection (mirrors).
It seems it would solve your problem, would it not?


Joao Pedrosa

unread,
Jan 4, 2013, 12:11:53 AM1/4/13
to mi...@dartlang.org
Hi Swarmii,

It's good to see other Rubyists around. I used Prawn (PDF generator) in Ruby a little and it was great fun. It's amazing that you ported some of it to Dart.

It's true that Dart lacks some of the things that were core to Ruby like meta-programming. I wouldn't expect much in the way of meta-programming in Dart, actually. The culture is a different one. Then again, Dart could keep on gaining features and unlike other languages that preceded it, Dart starts with a lot of dynamic baggage already like the optional types and the browser DOM.

Like you, I've also tried my hands at some meta-programming in Dart. My code was ported from JavaScript which had variable arguments to functions and checked for the existence of methods in objects to call them afterwards. While porting the code, I removed many use-cases of variable arguments because in most cases it didn't matter as much. In a couple of instances I kept some semblance of it by naming many arguments in advance to make room for pseudo variable arguments, just because I liked the API better that way, without an extra array or list wrapping them.

My meta-programming of Dart includes these 3 use-cases:

1. Checks for the existence of a method to call it. Not sure I used it for more similar cases.

2. Some variable arguments to make one of the most common APIs more pleasant to use.

3. And now that I recall it, I also use strings for DOM events to better control the what and how, while also making the API pleasant to use.

4. Many cases where I don't care about the type because the code can work from the same method with many different types.

We can do some meta-programming in Dart. It's just generally refrained from. I don't get over-excited about the Mirror Reflection of Dart, but it could eventually help to expand its meta-programming capabilities. In fact, I just tried to write some Mirror sample to give you an idea, and the Editor complained with "dart-mirrors is not fully implemented yet." Mirrors could be the way to go to call methods based on code input. Then there are the caveats that follow the Mirrors library.

Meanwhile, Dart comes with some ideas that it borrowed from a JavaScript library called jQuery that allows for code like this:

class SimpleCalc {
  var n1, n2, result;
  add() {
    result = n1 + n2;
  }
  printResult() => print("Result: ${result}");
}

void main() {
  new SimpleCalc()
    ..printResult()
    ..n1 = 10
    ..n2 = 30
    ..add()
    ..printResult();
}

=> Outputs this:

Result: null
Result: 40

I hadn't used that syntax before, as I use many short names for variables already. It's a nice feature of Dart though. It allows us to have long-ish variable names if we don't have to repeat them too often. :-)

I compare Dart to JavaScript in that Dart allowed me to see my code in better light so I could fix bugs, add features, remove useless code, and so on. I owe the Dart developers a lot for that. Dart and Ruby solve different problems so it's harder to compare them. All I can say is that Dart bodes well for larger code-bases, even if the intent is to not have too much code in the first place. :-)

Cheers,
Joao

SwarmShepherd

unread,
Jan 4, 2013, 2:56:06 AM1/4/13
to mi...@dartlang.org
Joao,

It's good to see other Rubyists around. I used Prawn (PDF generator) in Ruby a little and it was great fun. It's amazing that you ported some of it to Dart.

To explain: I used the Prawn Gem in 100's of lines of code, spending hours making my charts look just so, color tweaks, a pixel right, this line thicker, that kind of thing... for each of seven statistical studies, so I had a pretty big investment in that work, and doing what I did allowed me to avoid re-doing all that by effectively coming up with my own single class that serviced the original calls by using lower level Canvas context method.  It has surprised me how well it worked out - for my narrow and immediate purposes. 

I've actually been making some improvements of late - but only from the perspective of my narrow set of needs.  Dart and HTML5 are making it simple and amazingly fast.   

_swarmii



SwarmShepherd

unread,
Jan 4, 2013, 3:56:44 AM1/4/13
to mi...@dartlang.org
Alex,

There are hundreds of unique variables in my project,  so declaring them all seems like a lot of busy work to set up additional maintenance and potential debugging issues.  I would consider pre-declaring all the variables a considerable step backwards from where things are now (using the noSuchMethod method to access a Map).

_swarmii

Ladislav Thon

unread,
Jan 4, 2013, 4:39:27 AM1/4/13
to mi...@dartlang.org
It's true that Dart lacks some of the things that were core to Ruby like meta-programming. I wouldn't expect much in the way of meta-programming in Dart, actually. The culture is a different one. Then again, Dart could keep on gaining features and unlike other languages that preceded it, Dart starts with a lot of dynamic baggage already like the optional types and the browser DOM.

[...]

We can do some meta-programming in Dart. It's just generally refrained from. I don't get over-excited about the Mirror Reflection of Dart, but it could eventually help to expand its meta-programming capabilities. In fact, I just tried to write some Mirror sample to give you an idea, and the Editor complained with "dart-mirrors is not fully implemented yet." Mirrors could be the way to go to call methods based on code input. Then there are the caveats that follow the Mirrors library.


This is the important stuff. Dart doesn't refrain from metaprogramming -- it just makes it very explicit. There are performance costs associated with metaprogramming that are usually hidden behind the scenes in dynamic languages. Dart makes them obvious by requiring you to use a special API -- mirrors. Mirrors are metaprogramming in Dart, and they should eventually let you do almost everything that you can do in Ruby (generating new code, modifying classes, inspecting the call stack etc.). Right now, mirrors are very much a work in progress, but the basic stuff (calling methods based on dynamically computed names) works just fine. The API isn't exactly pleasant to use, but a small wrapper library could solve that.

But then, you're probably right that the culture is different. Dart's general approach to programming is also different, and that's where the culture comes from. Currently, my single-sentence explanation of Dart is: it's dynamically typed and statically structured. The approach to metaprogramming conforms to that.

LT

Alex Tatumizer

unread,
Jan 4, 2013, 9:46:45 AM1/4/13
to mi...@dartlang.org
I think mixins (as soon as they are implemented) will allow you to avoid declaring your vars in ever class:

You can declare all hundreds of variables in one class:
class MyVars {
  int XLoc;
  int YLoc;
  // etc
}

and then add MyVars as mixin to every chart class:
class Chart extends ChartBase with MyVars {
   // your functions
}

Would it solve your immediate problem?
(I an not sure you need ALL of the vars in every class though, so the solution is not ideal, but it will do the job)





Bob Nystrom

unread,
Jan 4, 2013, 12:42:26 PM1/4/13
to General Dart Discussion
Maybe I'm missing something, but would this work?

First, define this little class:

class DynamicFields {
  void bind(Map data) {
    _data = data;
  }

  noSuchMethod(InvocationMirror invocation) {
    if (invocation.isGetter &&
        _data != null &&
        _data.containsKey(invocation.memberName)) {
      return _data[invocation.memberName];
    }

    return super.noSuchMethod(invocation);
  }

  Map _data;
}

It basically gives you a way to dynamically add properties to an object by passing them to bind(). Then define your Chart class to extend it:

class Chart extends DynamicFields {
  void frame() {
    print('XLoc = $XLoc');
    print('Color = $Color');
    // Or whatever...
  }
}

And use it something like:

main() {
  var chart = new Chart();
  chart.bind({
    'with': 'chartFrame', 'fireAr': ["Chart.frame()"],
    'XLoc': 123, 'YLoc': 234, 'Height': 23, 'Width': 34,
    'Radius': 8, 'Thick': 4, 'Color': 'black'
  });
  chart.frame();
}

I'm probably missing something here, but is this in the vicinity of what you're trying to do?

- bob

Alex Tatumizer

unread,
Jan 4, 2013, 4:06:03 PM1/4/13
to mi...@dartlang.org
@Bob: I can't speak for _swarmi, but it looks like a good idea to me. Just a question of style:
suppose mixins are implemented, and you really know all the names/types in advance.
Would you (personally) prefer variant with mixins, or with noSuchMethod?
(mixins would require "bind" method to be implemented differently: use reflection to set up fields).

Thanks,
Alex

Chris Wright

unread,
Jan 4, 2013, 5:22:40 PM1/4/13
to mi...@dartlang.org
I would think that mixins are preferred until they become cumbersome. Use noSuchMethod as a quick (to code) but slow (to invoke) replacement for code generation.


Bob Nystrom

unread,
Jan 4, 2013, 5:33:02 PM1/4/13
to General Dart Discussion
On Fri, Jan 4, 2013 at 1:06 PM, Alex Tatumizer <tatu...@gmail.com> wrote:
Just a question of style:
suppose mixins are implemented, and you really know all the names/types in advance.

If I know the names and types in advance, then I'd prefer to have that baked in like you suggest instead of noSuchMethod. Dynamism is nice, but it basically kills any tooling based on static analysis. I make lots of typos, so breaking the tool's ability to help me find them is a drag.
 
Would you (personally) prefer variant with mixins, or with noSuchMethod?

If I did go with noSuchMethod here, I probably would make that DynamicFields class itself a mixin, though. It's a perfect candidate for being a mixin.

Cheers,

- bob

George Koller

unread,
Jan 4, 2013, 6:05:06 PM1/4/13
to mi...@dartlang.org
Bob,

Your example looks to be exactly what I've been looking for.  It looks to allow me to access variables by name rather than a function name.  

Thanks a million!  

Give me a few days from this point to test this out and see how it works.

For those wondering what the difference is let me explain that when we design a new study from some point going forward, some 80% of the new work will be related to getting the right values in the right places.  So while this may seem not a big thing to a "systems" programmer, it is an important part of the smaller, more concise programming environment from the applications perspective.  Hope this makes sense.  

=====

Reflecting more on all this, I'd just like to say that if we achieve this properly (imho) then if you follow the chain of things that have to happen to introduce a new feature to one of the graphical studies there should only be a need to:

1.  Add a single new method (doing graphics at a nice high level) to the appropriate class in the Graphics support library.

2.  Then for all the studies that will use this new feature, simply add a new method to feed the needed data  (in the form of a nice flexible map).

In my opinion, this is a nice thing to work for and in Ruby it was doable.  With my newness to Dart and this family of software and lack of experience with HTML/CSS and all it has been a bit of struggle to find ways to keep things this simple.   

My other design compromise, that I mentioned above is that I used nasty, ugly, old fashioned switch statements to call the appropriate Class and Method - to bring the data of #1 with the Code of #2 together.  

When one has been able to do these dynamic things with almost trivial amounts of code  then blocks of code doing things like switch statements start looking "ugly" .

So I'm looking for a way to do a class & method invocation on a string name and I'll have the two biggest glitches to the Dart version smoothed over, and I'll be a very happy camper!

I'll detail the problem in another posting soon, into this thread.

Thanks again!


_swarmii

Yohan BESCHI

unread,
Jan 4, 2013, 6:59:22 PM1/4/13
to mi...@dartlang.org
Despite the fact that it’s completely against all OO programming and that Type checking is impossible before runtime the noSuchMethod() way is nice.

What I’ve been using is really close to this :

class User extends DynaBean {
  static final String fn = 'firstName';
  static final String ln = 'lastName';
  static final String ag = 'age';
 
  User.empty() : super() {}
 
  User(String firstName, String lastName, String age) : super() {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }
 
  void set firstName(v) {_map[fn] = v;}
  void set lastName(v) {_map[ln] = v;}
  void set age(v) {_map[ag] = v;}
 
  String get firstName => _map[fn];
  String get lastName => _map[ln];
  int get age =>  _map[ag];
}

class DynaBean {
  Map<String, Object> _map;
 
  DynaBean() {
    this._map = new Map();
  }
 
  Object get(String key) {
    return this._map[key];
  }
 
  void set(String key, Object value) {
    this._map[key] = value;
  }
}

George, for your Class/method instanciation/invocation at runtime could something like this help ?

void main() {
  final Map<String, Function> providers = {'MyClass': () => new MyClass()};
 
  // Get a new instance of MyClass
  final SuperClass superClass = Function.apply(providers['MyClass'], null);
  // Call the method printText
  superClass.callMethod('printText', ['Hello']);
}

abstract class SuperClass {
  Map<String, Function> methods;
 
  SuperClass() {
    methods = {'printText': (s) => this.printText(s)};
  }
 
  callMethod(String methodName, List params) {
    Function.apply(methods['printText'], params);
  }
 
  printText(String s);
}

class MyClass extends SuperClass {
  printText(String s) {
    print(s);

Tom Yeh

unread,
Jan 4, 2013, 10:35:54 PM1/4/13
to mi...@dartlang.org
@bob,

Evaluating a closure that accepts any kind of objects as arguments and references some global variable/function/class is #1, right? For example, can the following statement be evaluated at run time?

Foo dynamicGenerated(Something obj) => new Foo(obj.whatever);

/ tom

On Friday, January 4, 2013 2:34:04 AM UTC+8, Bob Nystrom wrote:

SwarmShepherd

unread,
Jan 5, 2013, 1:42:12 AM1/5/13
to mi...@dartlang.org
  Yohan,

 Have worked on this tonight and have something working now.  I used your basic idea but tied some other ideas together into a class with two methods.

The first method just basically builds a map of class+string names as the key, and an invoke-able reference as the value. 

The 2nd method takes a String of className.methodName as the key, looks this up in the map and bing bang boom the code is executed with all the necessary handling.

Truth is that I have worked now an additional 6 hours to trade 120 or so lines of "hard coded ugly switch statements" for some pretty fragile looking  / a bit too involved (lots of string manipulation)  for my taste code that does the trick.  

Has it been worth it?  

It was CLEARLY the way to go to my thinking in Ruby - it was a Win Win.   Not so much in Dart, not  as things lie.   However, although its been a a struggle I think its going to be well worth it because, as I attempted to elaborate already, this is where our future work will be focused and I wanted to just add new methods and let this reflection stuff just adopt to these changes.  

Here's some of the code, but its full of my helper functions, but will probably make sense... 

class ClassMethodMapper {  
 
Map    _helperMirrorsMap;


 
Map _class_map(Map methodMap, Object myClass){
   
InstanceMirror helperMirror = reflect(myClass);
   
List methodsAr  = helperMirror.type.methods.values;
   
String classNm  = myClass.toString().split("'")[1];  


    MAP_add
(_helperMirrorsMap, classNm, helperMirror);


    methodsAr
.forEach(( method) {
     
String key = method.toString().split("'")[1];
     
if (key.charCodeAt(0) != 95) { //'_'    
        key
= "${classNm}.${method.toString().split("'")[1]}";
        MAP_add(methodMap, key, method);
      }
    });
    return(methodMap);
  }


  Map  invoker( methodNm, methodMap ) {
    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() {    
    Map    methodMap   = {};
    _helperMirrorsMap  = {};
   
    //Accumulate a class level Map of all methods, prefixed by class name
    //as key, and method ref as value.
    _class_map( methodMap, new Page(null)   );
    _class_map( methodMap, new Chart(null)  );
    //...

    h2("methodMap = ${methodMap}");

    invoker( "Chart.frame", methodMap );
    invoker( "Page.title",  methodMap );
  }
}


Seems like a decent start on it, the string handling just seems "fragile" :)

Thanks!

_swarmii
Reply all
Reply to author
Forward
0 new messages