dart-pad icon indicating copy to clipboard operation
dart-pad copied to clipboard

SynchronousFuture behavior is different depending on the SDK

Open johnpryan opened this issue 4 years ago • 7 comments

The behavior of a SynchronousFuture is different dependeing on whether the Dart SDK or Flutter SDK is used. The Dart SDK executes immediately, but the Flutter SDK does not:

johnpryan avatar Oct 06 '21 17:10 johnpryan

Have you tested these on the VMs?

Hixie avatar Oct 06 '21 18:10 Hixie

Another reason they might differ is that in the Flutter case we wrap main() in a bunch of Zone magic.

Hixie avatar Oct 06 '21 18:10 Hixie

It looks like this only happens when a Flutter app is compiled to JS:

Platform sync async
Web (Dart) X
Web (Flutter) X
VM (Dart) X
VM (Flutter) X

FYI @yjbanov

johnpryan avatar Oct 07 '21 20:10 johnpryan

Update: this is only happening with DDC. (DartPad uses DDC for Flutter code)

johnpryan avatar Oct 07 '21 20:10 johnpryan

I'm surprised that we're able to subvert the asynchrony of await on any platform...

@lrhn - were you aware of this behavior?

natebosch avatar Nov 02 '21 00:11 natebosch

It's unsurprising that things break when you implement Future incorrectly. Since await is defined in terms of calling then, and then is specified as not calling the callback during the then call, weird things happen if you do so anyway. We don't (necessarily) add extra overhead to try to avoid implementations of Future which are broken. We also don't try to keep our implementations bug-compatible. If your Future doesn't behave like a proper future, we can go off the rails in different ways on different platforms.

Basically, it's unspecified behavior. If it hurts, stop doing it.

Nothing prevents you from creating a Stream which calls its event callbacks after you've called cancel, or after sending a done event, or sending more than one done event, or creating a future which calls the then callback more than once, or both the data and error callbacks. It breaks assumptions that other code might be based on, and the behavior of the platform is undefined if you do so. Same if your Future calls the callback in during the call to then.

(Also, the specification of await doesn't say when execution continues:

The current invocation of the function body immediately enclosing $a$
is suspended until after $f$ completes.
At some time after $f$ is completed, control returns to the current invocation.

so, it's not wrong to be asynchronous, no matter when the future calls then. We actually do try to make it continue within the same microtask queue, but that is it.)

lrhn avatar Nov 02 '21 11:11 lrhn

Related to https://github.com/flutter/flutter/issues/82827

johnpryan avatar Nov 03 '21 21:11 johnpryan