Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mirrors: Provide synchronous equivalents to async APIs #4633

Closed
DartBot opened this issue Aug 21, 2012 · 19 comments
Closed

Mirrors: Provide synchronous equivalents to async APIs #4633

DartBot opened this issue Aug 21, 2012 · 19 comments
Assignees
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). type-enhancement A request for a change that isn't a bug

Comments

@DartBot
Copy link

DartBot commented Aug 21, 2012

This issue was originally filed by prujohn...@gmail.com


Understanding from this thread

https://groups.google.com/a/dartlang.org/forum/#!topic/misc/AoaiQnCWD4w

that many of the instancing pieces of the current mirror API are asynchronous, because of the (requirement?) to provide cross-isolate reflection.

I would like to propose that there be synchronous equivalents to these APIs, where cross-isolate reflection is naturally restricted. This is based on the assumption that most reflective work will occur in the current isolate context. I am finding this to be true in my case, anyhow.

The future-based API works well (I have a branch of Buckshot that is building templates dynamically using it now: https://github.com/prujohn/Buckshot/blob/mirrors/lib/templates/XmlTemplateProvider.dart), but it introduces more overhead and complexity to the application control flow, and is more difficult to debug.

@gbracha
Copy link
Contributor

gbracha commented Aug 21, 2012

There is a lot to say about this issue.

a. I expect Dart's support for asynchronous programming to evolve so that it is considerably less onerous. That said, the async version will never be as easy as the synchronous one.

b. We are trying to keep the async parts to a minimum. Once you get an object, you can introspect synchronously on its code. Almost all of the planned mirror builder API is synchronous.

c. It is a goal (admittedly ambitious) to make reflective code work cross-isolate. There are just too many examples of tools that would be very useful in a distributed setting, but were designed without distribution in mind. We'd like the norm for Dart reflective tools to be cross-isolate.

So, before we admit defeat (and before the API is even complete) we'd like to stick to the plan. If, when all is said and done, we find that it is still too painful to handle local reflection, we can always give up then - and we may; I'm not saying that we shall never surrender. However, we shouldn't surrender prematurely.


Set owner to @gbracha.
Added this to the Later milestone.
Added Area-Language, Accepted labels.

@DartBot
Copy link
Author

DartBot commented Aug 21, 2012

This comment was originally written by pr...@gmail.com


Appreciate your comments Gilad.

Regarding item 'c'. I certainly agree with the potential benefits of cross-isolate reflection. My argument is (admittedly more based on intuition than data) that the majority of the reflection-usage scenarios will remain within the same isolate context, and so a synchronous peer of the async API would seem quite useful.

And certainly: Don't give up! :)

@gbracha
Copy link
Contributor

gbracha commented Aug 21, 2012

Removed Type-Defect label.
Added Type-Enhancement label.

@DartBot
Copy link
Author

DartBot commented Nov 20, 2012

This comment was originally written by gp7...@gmail.com


Hi,

I miss synchronous mirror operations as well.

And I do not understand why the ambition of the Dart team to use only the asynchronous variants could be a reason to leave out the synchronous variants which have their own use cases.

For now my solution looks like this:
  invoke(){
    Future<InstanceMirror> x = mirror.invoke(memberName, args);
    while(!x.isComplete){
      continue;
    }
    if(x.exception == null){
      InstanceMirror m = x.value;
      return m.reflectee;
    }
    return x.exception;
  }

The while loop is just silly and might be technically inefficient.

 

@DartBot
Copy link
Author

DartBot commented Nov 20, 2012

This comment was originally written by ladicek@gmail.com


gp789...: The while loop is not only silly, it also can't possibly work. Never ever. Just don't do that. The reason why it looks like it's working is that mirrors are synchronous right now, so the loop body is actually never reached. The reason why it won't work once mirrors become asynchronous is that async code in Dart doesn't necessarily mean parallel code. You will fire a request to the mirror library and continue in your own code. Once your code will give up, event handlers for completed events will be called. But you will never give up, as you just entered an infinite loop. Seriously, infinite loop is always terrible idea, but it's even more terrible in Dart where code can't be interrupted by other code.

@DartBot
Copy link
Author

DartBot commented Nov 20, 2012

This comment was originally written by gp78...@gmail.com


Ladislav, thank for your comment and explanation.
What would be the Dart community without you :)

Unfortunately I do not understand your objection.
Should the future.isComplete field not terminate the loop ?

@DartBot
Copy link
Author

DartBot commented Nov 20, 2012

This comment was originally written by gp789654...@gmail.com


So you mean that the system passes the single thread to my loop code and never switches back to the "invoke" method ?

I hope the Dart team does think about such cases when implementing their thread scheduling.
And this is one more reason to introduce synchronous variants as soon as possible.

@DartBot
Copy link
Author

DartBot commented Nov 20, 2012

This comment was originally written by ladicek@gmail.com


That's about right. It isn't exactly about thread scheduling, it's about doing async in one thread (because that is what actually happens -- there is no multithreading inside single isolate). Or, if you prefer, you can think about it as cooperative multitasking -- each "thread" has to give up sometimes so that other "threads" can work too -- except that here, "thread" doesn't mean real parallel thread, but rather a sequence of synchronously processed instructions, and "give up" actually means finishing the sequence to the end.

@DartBot
Copy link
Author

DartBot commented Nov 20, 2012

This comment was originally written by gp7...@gmail.com


I can understand that Javascript switches the task when the (event handler) code has finished.
But since Dart has a main method, I have thought that Dart was using some kind of preemptive multi-tasking behind the scenes even when Javascript is used for the implementation.

So there is no way to have synchronous mirror operations for now ?

@DartBot
Copy link
Author

DartBot commented Nov 20, 2012

This comment was originally written by gp7...@gmail.com


Well for now it works.

But it is important to have an answer from Google that if things become asynchronous, that there will be synchronous variants.
Otherwise my current work becomes useless.

And for now I can not continue my work because of this issue.

@gbracha
Copy link
Contributor

gbracha commented Nov 20, 2012

If we prevent the async version working synchronously in the same isolate, there are two possibilities:

a. Code that relies on the synchronous behavior has to be revised to account for the possibility of asynchrony.
b. A synchronous API is added, that works only within an isolate.

We have not decided which of those paths to take. Each has advantages: (a) means that al reflective code works in a distributed setting. (b) means there is an easy path for code that only works in a single isolate.

@DartBot
Copy link
Author

DartBot commented Nov 21, 2012

This comment was originally written by gp78965...@gmail.com


Thank you for the response.

For a simple implementation of an interpreter I was trying to make any use of Dart libraries via Mirrors.

@jmesserly
Copy link

I don't think (a) can possibly work. Not every bit of code can magically work in a distributed setting. Things like evaluators/inspectors/debuggers need to be constructed intentionally, and they will no doubt want to use some degree of asynchrony. But there are a ton of use cases for reflection that need to be synchronous. By requiring async, it means mirrors will not be used in those scenarios, leaving Dart with less dynamic capabilities than many competing languages.

@DartBot
Copy link
Author

DartBot commented Feb 6, 2013

This comment was originally written by Seth.Il...@gmail.com


Agreed with the point that (a) cannot possibly work for everyday coding. An excellent example is JSONObject (https://github.com/chrisbu/dartwatch-JsonObject). This is very useful library, but since it uses reflection, it returns futures. This is highly undesirable for my codebase, and I would imagine many others.

If only we had wait() or yield() in the language, we would get the best of both worlds, but that is a separate discussion, on a separate bug.

@gbracha
Copy link
Contributor

gbracha commented Feb 6, 2013

John,

Having returned to look at this issue recently, I'm inclined to agree. In the current state of play, using async methods in the mirror API spreads the async contagion to the API of the user, and so forth ad nauseum. This was not the case with the policies in place when we first designed the API. So I lean toward (b). It shouldn't be to hard to make that change, and worry about the remote reflection case later. We'lls ee what others think though.

@DartBot
Copy link
Author

DartBot commented Feb 6, 2013

This comment was originally written by @chrisbu


That's good to hear. I suspect that option b would cover a majority of use cases for reflection.

@DartBot
Copy link
Author

DartBot commented Feb 24, 2013

This comment was originally written by @sethladd


Very great to hear, thanks for reconsidering!

@DartBot
Copy link
Author

DartBot commented Mar 11, 2013

This comment was originally written by greg...@gmail.com


I recently bumped into this too. Here's my use case in case it helps:

Assuming:

class Person {
  String firstname;
  String lastname;
}

Stream<Map<String, dynamic>> query(String sql) { ... }

This is what I'd like to be able to do:

query("select firstname, lastname from person")
  .map(createMapper(Person))
  .then((person) {
    print(person);
  });

This is pretty simple when done synchronously:

createMapper(Type type) {
  var classMirror = reflectClassMirror(type); // +1 #­8041
  return (Map<String, dynamic> row) {
     var instanceMirror = classMirror.newInstance(null, []);
     for (var key in row.keys) {
       instanceMirror.setField(key, row[key); //TODO check field exists.
     }
     return instanceMirror.reflectee;
  };
}

I started to write the async version of this, but gave up. I think you need to pause and restart the Stream for each event.

@DartBot
Copy link
Author

DartBot commented Apr 17, 2013

This comment was originally written by LouisSt...@gmail.com


Looks like there's been progress on this one :) https://code.google.com/p/dart/source/detail?r=21591

@DartBot DartBot added Type-Enhancement area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). labels Apr 17, 2013
@DartBot DartBot added this to the Later milestone Apr 17, 2013
@kevmoo kevmoo added type-enhancement A request for a change that isn't a bug and removed type-enhancement labels Mar 1, 2016
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

4 participants