-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Permit sending arbitrary closures through ports within isolate group on the VM #40370
Comments
/cc @mkustermann @a-siva |
Closures can contain references to local variables. It's unclear what would happen if you send two closures referring to the same local variable—will they refer to the same location when they are received as well? What if you send them in separate messages on the same port? Will closures sent through a port preserve equality? Identity? If a closure references both local and global variables, will it clone the local closure, but use the other side's global state? That can break any number of invariants (but then, an object suffers from that same issue, it can contain its own state and refer to global state as well, and sending it to a different isolate can make those out of sync). Sending closures is definitely possible, but I'm not sure the behavior is predictable enough that it's desirable. Too many footguns. |
@lrhn Given that you can send an instance of a class like this:
What is the difference between sending this and a real closure? In my eyes not much. All the same questions and concerns apply.
So why do we permit sending |
It has always been the plan to lift this restriction with isolate groups. Though it is true that sending arbitrary closures can have unexpected behavior, because of the Dart VM's implementation of captured variables: We capture more than necessary, which can significantly increase the transitive graph to copy due to context sharing and not capturing final instance field values but rather the Partially this is also an implementation problem atm, where we can have deeply nested inner closures where we would need to be able to identify the corresponding By sharing the entire program structure within an isolate group, this is trivial because the sender and receiver |
The big difference is closing over local variables. To do that, you need to clone the closure as part of cloning the function. That again means that you no longer refer to the same variable. That makes it unpredictable what happens if you send such a closure. Sure, we can just say that that is the case, and that you shouldn't modify (or depend on) local variables in the functions you send, but we still have to give it a semantics when it happens. If you send a function that you receive as an argument, not one you define yourself, you have no way to predict what it will include when serialized. |
Slightly off topic, but is there any desire to fix/change this? This can dramatically (asymptotically actually) increase memory usage in a very hard to diagnose way. I have, concretely, run into this problem on other platforms in the past. |
Other issues aside, I have no objections with ignoring web-only restrictions. (At some point, we will probably want a common abstraction for concurrency. I don't |
Returning to this request:
I am still not sure what's the big difference between local variables and object fields - to me these are two completely isomorphic concepts, so I don't believe anybody would be surprised that when you send a closure across the port and then send it back you get a copy of this closure closing over a copy of your state. Though I must acknowledge that our implementation of closures might result in unobvious amount of state being copied to another isolate due to parent. We could address this issue by tracking exactly which variables are referenced by a specific function (and its nested functions) and pruning context on serialisation. In any case it seems that there is strong opposition to this proposal from either the language team or web team - so we could actually move forward and expand Dart VM capabilities here. |
As mentioned in #40370 (comment) our plan is to lift this restriction when isolate groups are fully implemented (that makes it safer with regards to hot reload and avoids hacks to identify correct closure function on receiver side) |
The difference is that users understand what an object is. If I wrote the class, I can control which fields it has and which values it keeps references to. When I send an object, its state is copied and the result is again an object. It's a copy, so it has a different identity, but that's all well-known concepts. A closure retains references to some local variables, whatever those really are. It's not clear which variables are closed over, and there is no way to control it. It's the latter part which worries me the most, and that users won't understand what's going on. And why local variables are closed over, but global ones are not. One consequence of sending local functions is that the argument to (Can you send an |
This is where I insert my obligatory note that this can be (and I would argue should be) fixed. |
I think the time is ripe to try. We will track the work in #36983 - I am a bit worried that it might lead to worse code size than the current implementation, but I think leaks are bad enough to warrant trying. |
We currently prohibit sending arbitrary closures through ports. I think this restrictions originates from the web where it is impossible to send a closure represented as a JS closure through a port to a web worker. This restriction however does not make any sense in the VM.
I suggest lifting it unless somebody has any objections.
/cc @leafpetersen @lrhn @vsmenon
The text was updated successfully, but these errors were encountered: