-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Using ExternalDartReference
as a function parameter is expensive
#55342
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
Comments
@leonsenft - can you clarify, is this function that you are passing to JS going to be invoked from JS, or only passed back to Dart opaquely? |
Thanks! I see what you mean now. So tricky! @srujzs - I'm wondering if it's possible for the interop library to have a higher order conversion. That is, just like Not sure how compatible this is with the Wasm support, though. More generally - we also currently don't specialize the conversions we use in allowinterop, so potentially we could also do better there. For example, the current default will use |
So essentially a
I think it's a good idea to speed up As a side comment, I'm a little confused by this:
Since we're eliding casts with |
Yeah that confused me as well. If I replace my implementation of @JS('u')
external void _update(JSExportedDartFunction update);
/// Update the value of the signal based on its current value, and notify any
/// dependents.
void update(T Function(T) function) {
_update(trustAs<ExternalDartReference? Function(ExternalDartReference?)>(
function)
.toJS);
} It produces this error at runtime:
I'm not sure what |
Oh, does DDC respect |
Confirmed that the test passes with dart2js, but not DDC. Is there a pragma for DDC? |
Oooh, sorry, I see what you meant by parameter now - yes, the contravariance is an issue. I don't think there's a way for DDC to elide type-checks with pragmas. |
I mention one possible solution in #55536, where we make void update(U Function(U) function) {
_update((function as ExternalDartReference<U> Function(
ExternalDartReference<U>))
.toJS);
} The other alternative might be to make the bound void update(U? Function(U?) function) {
_update((function as ExternalDartReference<U>? Function(
ExternalDartReference<U>?))
.toJS);
} Here, Of course, either way, such a cast won't work on dart2wasm (I figure you likely don't care about dart2wasm for now). We'd need to do something like the proposal in #55342 (comment) for a consistent API. I'm generally against such an API for at least two reasons:
That being said, an interesting alternative to this is to have a "Function.toJSAllExternalReferences" where the only applicable conversion is to and from |
Consider the following example. Passing a Dart function with a JS incompatible parameter requires wrapping it to do conversions on the argument(s) and return type:
This produces an extra closure object, and despite using techniques to optimize away the cost of the conversions (see #55339), the closure remains:
Note that the
A.WritableSignal__jsCompatibleFunction()
call doesn't actually do anything. It simply forwards its argument to the closure it wraps. This code is equivalent to:For reference this is essentially what I had before migrating to
dart:js_interop
, so I think there's still room to improve here and get performance parity withpackage:js
.As a side note, if the Dart function has no parameter, and only a return type, we can cast/convert it directly:
This doesn't work with the example above because we can't cast a Function type with a parameter to a broader type.
The text was updated successfully, but these errors were encountered: