[experiment] Automatically patch Pyodide callbacks on main #79
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Background
Pyodide requires create_proxy not only for event listeners but also for any JS API that might use a callback that is not instantly invoked:
watchPositionand othersPyodide did an excellent job in explaining how to work-around but we're having hard time justifying some inconsistency with events themselves or the fact users need to think about when a callback should be wrapped and where it shouldn't.
Following a few examples of such inconsistencies:
There are also cases, such as Promise and generaters, that automatically take care of the callback life span, or create once, or proxy, and we think this might be confusing to reason about from new comers to people coming form JS that know what they are doing but need to learn a foreign API to do what used to be simple.
Bear in mind with MicroPython most of these issues don't exist, so we also have inconsistent Python behavior for, again, what's usually simple to deal with on the Web.
Last, but not least, with the latest ability to load 3rd party JS libraries, the error around callbacks that are passed within 3rd party APIs and nobody can dictate what happens with those callbacks internally and when or why a proxy or a once should be used, we decided to have a conversation and explore possible solutions ... and this MR is the result of such exploration.
Proposal
We cannot possibly patch all DOM APIs that use callbacks or all 3rd party libraries that accept callbacks as argument so that I've had the insane idea of patching the source/root of the problem: the usage of
callandapplythat, whenever a context is meant to be passed or the amount of arguments is variable, are the most basic primitive any library could use, including Pyodide.We understand such patch might feel wrong and we'd love to never need to do so, but as our users and the DX or UX of the project is something we really care about, we decided to try at least to see if making this feature opt-in and for Pyodide only, could somehow actually work well.
This MR hence propose the following:
experimental_create_proxy = "auto",apply once a patch forcallandapplyonly on main and only if the interpreter is Pyodidecallorapplyfunctionality unless the Python code is running ... meaning:run(pythonCode)orrunAsync(pythonCode)orrunEvent(...)such flag is switched totruetypeofarguments that are function and aninstanceofPyProxy, keeping untouched any other kind of argument.destroy()those callbacks transparentlyThis MR is up for discussion but basically allows an explicit opt-in that could be warned as experimental so that both we, pyodide folks, or our users, can provide feedback, tell us if anything degraded performance, and so on so please feel free to join the conversation and tell us what you think about this MR, thank you!
To Be Discussed
The original idea was to also have a way, whenever that desired or needed, to avoid wrapping or copying callbacks via a
direct(callback)utility by this module where such utility would be just an identity for all other interpreters but it will instrument pyodide to skip wrapping or checking a specific callback as argument:This would be a probably welcome escape hatch for those specific cases where no copy is ever desired but ideally this could be instead provided by pyodide if they'll ever decide that using GC to automatically handle memory is a possible way forward.