Skip to content
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

Support Synchronous evaluation of FutureOr #726

Open
creativecreatorormaybenot opened this issue Dec 6, 2019 · 4 comments
Open

Support Synchronous evaluation of FutureOr #726

creativecreatorormaybenot opened this issue Dec 6, 2019 · 4 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@creativecreatorormaybenot
Copy link
Contributor

creativecreatorormaybenot commented Dec 6, 2019

Feature request

When we have a variable FutureOr<int> futureOr, await futureOr should run synchronously when the variable is not a Future (see https://stackoverflow.com/q/59213196/6509751).

Current situation

At the moment, you need to use the following code if you want to run the evaluation synchronously when possible:

if (futureOr is int)
  print(futureOr + 9);
else
  print((await futureOr) + 9);
@creativecreatorormaybenot creativecreatorormaybenot added the feature Proposed language feature that solves one or more problems label Dec 6, 2019
@creativecreatorormaybenot
Copy link
Contributor Author

cc @rrousselGit

@rrousselGit
Copy link

rrousselGit commented Dec 7, 2019

Thinking about it, I wonder if it's not for backward compatibility with JS?

I don't see any other explanation.

Although I'd expect dart2js compiler to be able to convert Dart await calls to something like:

let futureOr;

let result;
if (futureOr instanceof Promise) {
  result = await futureOr;
} else {
  result = futureOr;
}

@lrhn
Copy link
Member

lrhn commented Dec 9, 2019

It's not for compatibility with JS.

The original discussion in Dart 1 was whether to allow await e where e was not a future at all. It was decided to allow it, and when the value was not a future, it was turned into a future and that future was awaited. That gives the most consistent behavior.
A significant amount of code now depends on await null actually delaying until a later microtask, so changing it is tricky.

Dart 2 is more strictly typed, but we still allow you to await non-futures. Some would argue that that was a mistake, but it had the advantage that it works with FutureOr, which was introduced in Dart 2.0 because of all those places where the Dart 1 type system allowed us to pass a future or a non-future. If we had designed the APIs from scratch for Dart 2, there probably wouldn't have been any FutureOr type, but alas, we didn't.

That all means that the current behavior of await e, even though was specified with Dart 1 in mind and only updated slightly for Dart 2, is still what all existing code is written against, and changing it now will certainly be a breaking change.
It may also make ahead-of-time compiled async code larger because it will need both a synchronous code path and an asynchronous code path for the same code, in case the value is not a future (which currently includes being null, which we'd have to assume on every await until we get non-nullable types).

@rrousselGit
Copy link

rrousselGit commented Dec 10, 2019

Would it make sense to have a maybeAwait keyword then?

This would avoid having to use something like SynchronousFuture from Flutter.

We can technically do:

if (futureOr is int)
  print(futureOr + 9);
else
  print((await futureOr) + 9);

But there's no way to factorize it without resorting to something similar to .then, which leads to pretty nested code – await being more readable.

It's not a critical feature though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

3 participants