Description
Change Intent
waitFor
contradicts Dart's event-loop model in a way that no other old or new feature does: it allows async and synchronous code to interleave. The feature has been marked experimental since the beginning and effectively has only two users: sass and dcli package. It is not available in Flutter or on the Web because dart:cli
library is not exposed there.
See discussion on #39390 for context.
Justification
We would like to reduce VM's technical debt by removing this experimental functionality, which we believe was added hastily and without due thought to the consequences.
We also have some indications (based on some internal code which has been migrated from waitFor
) that availability of waitFor
encourages ineffecient and convoluted coding patterns.
If you compare waitFor
with Finalizer
(which was added in 2.17) you will observe that we choose to make Finalizer
less powerful by specifying that finalizers are only invoked at the turn of the event loop for the sake of maintaining semantic purity around interleaving of synchronous code.
Impact
Current users (which basically amounts to dcli and sass) will have to migrate off waitFor
which will require them to rewrite their code.
Mitigation
Based on our analysis of dcli and sass multiple migration strategies are available:
- The usage of asynchronous
dart:io
methods can be replaced with synchronous counterparts, eliminating the need forwaitFor
; - Asynchronous code can be moved to a helper isolate which communicates with the main isolate through synchronous communication channel built on top of low-level
dart:ffi
primitives; - Synchronous code be rewritten to become asynchronous, following Dart's canonical style for writing such code.
Note that it is an explicit non-goal to provide a completely equivalent replacement for waitFor
, because we believe the feature itself is incompatible with how Dart's async is designed and should be removed.
Synchronous communication over dart:ffi
This code demonstrates how dart:ffi
can be used to establish an entirely synchronous communication channel between the main (dispatcher) isolate and a worker isolate. This type of communication channel should cover sass needs.
To make migration simpler we will provide a portable synchronization package which implements mutexes and conditional variables, though we leave implementation of cross-isolate communication channels to the developers.
Isolate.resolvePackageUri
Some minor users of waitFor
use it to synchronously unwrap Future
returned from Isolate.resolvePackageUri
API. In reality the underlying implementation of Isolate.resolvePackageUri
is entirely synchronous.
While there is migration path for this code using dart:ffi
and isolates we can simplify things by directly exposing Isolate.resolvePackageUriSync(...)
and deprecating async version of this API.
Timeline
The removal will follow this timeline:
- Dart 2.15: The
waitFor
feature was marked deprecated - Dart 3.0: We announce the upcoming removal, offering ~1 year migration timeline
- Dart 3.3:
waitFor
is now disabled by default, but can be temporarily enabled by passing the flag--enable_deprecated_wait_for
to the VM /dart
command - Dart 3.4: We'll fully remove
waitFor
and there will be no way of enabling it
Metadata
Metadata
Assignees
Labels
Type
Projects
Status