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

Prefix await is cumbersome to work with. #25

Open
lrhn opened this issue Sep 13, 2018 · 11 comments
Open

Prefix await is cumbersome to work with. #25

lrhn opened this issue Sep 13, 2018 · 11 comments
Assignees
Labels
request Requests to resolve a particular developer problem small-feature A small feature which is relatively cheap to implement.

Comments

@lrhn
Copy link
Member

lrhn commented Sep 13, 2018

In an asynchronous Dart function, the await expr expression allows blocking and waiting for a future result of expr to complete.
This is highly convenient compared to using Future.then, but grammatically it's still cumbersome because await is a prefix operator with lower precedence than selectors.
Example:

var x = await (await foo.bar()).baz();

If you need to await an intermediate result of a longer computation chain, you need to add parentheses and go back and write the await far distanced from the operation that created the future.

If you have a cascade like:

expr
  ..bar()
  ..baz()
  ..qux();

and baz is (or becomes) asynchronous and you want to await it before continuing, then you have to rewrite it to something like:

var tmp = expr..bar();
await tmp.baz();
tmp..qux();  // or one dot, doesn't matter.

A possible improvement would be to allow await as a suffix operator instead of a prefix operator:

var x = foo.bar() await.baz() await;
expr
  ..bar() 
  ..baz() await
  ..qux();

or maybe with a dot in front:

var x = foo.bar().await.baz().await;
expr
  ..bar()
  ..baz().await
  ..qux();

This is still only allowed inside asynchronous functions where await is a reserved word, so it would not be ambiguous.
Other alternatives could be a suffix operator (like !, although that's probably high-priced syntactic real-estate, but if it is a general heuristic coercion operator, it could coerce from Future<T> to T too) or something else that allows binding await better in compound expressions.

@lrhn lrhn added the request Requests to resolve a particular developer problem label Sep 13, 2018
@lrhn lrhn self-assigned this Sep 13, 2018
@pschiffmann
Copy link

pschiffmann commented Jan 26, 2019

Idea: Special-case the await keyword to be a valid RHS for the |> operator from #43. It could look like this:

/// Changes the contents of [file] to uppercase.
/// Completes when the file is written back to disk.
Future<void> contentsToUpperCase(File file) async =>
    file.readAsString()
      |> await
      |. toUpperCase()
      |> file.writeAsString
      |> await;

@fkettelhoit
Copy link

Is this still being considered? It looks like this would be a very small non-breaking syntactic change, but would make working with nested futures much more pleasant. For example, I'm currently working with records that form a graph in a database so that each record has a children getter of type Future<List<Record>> (these graphs can be cyclic, so I do not want to immediately load the children and their descendants). Right now this forces me to write call chains like the following:

final someChild = (await (await (await db.get(someId)).children).first.children).first;

With the proposed postfix await this would become much less cumbersome:

final someChild = db.get(someId).await.children.await.first.children.await.first;

(Of course something even shorter than .await would be great, but now that ! is already used for NNBD I would personally already be very happy with .await or any postfix solution really.)

@mateusfccp
Copy link
Contributor

mateusfccp commented Jun 25, 2020

@fkettelhoit

In these cases I will simply use .then, as function chaining is way clearer than await chaining...

final someChild =
    await db.get(someId)
            .then((o) => o.children)
            .then((o) => o.first.children)
            .then((o) => o.first)

This would be even better if we could have something like #691.

@lrhn lrhn added the small-feature A small feature which is relatively cheap to implement. label Jul 8, 2020
@Jonas-Sander
Copy link

To be honest I think

expr
  ..bar() 
  ..baz() await
  ..qux();

and

expr
  ..bar()
  ..baz().await
  ..qux();

are kinda confusing because I'm just so used to seeing await infront of the Future.
I think the ..baz().await at least shows that the await does indeed wait for baz, in the other one I thought await would wait for qux() at first.

Maybe I'm just boring, but what about this?

expr
  ..bar() 
  ..await baz()
  ..qux();

The only thing i don't like about it is that baz is not directly under bar but I think it's still good enough to quickly scan over.

@lrhn
Copy link
Member Author

lrhn commented Jul 10, 2020

Putting the await before the method call is something I have otherwise thought of, also for other prefix operators.

The await foo().bar() issue is also a problem for !foo.bar(). If you could put prefix operators inside a selector sequence, then you could write that as foo().!bar() (which is perhaps more readable as list.!isEmpty).

It doesn't really work as an incremental change, though. To do this, it would mean that foo.!bar.baz should bind to the bar, not the bar.baz, but then it's inconsistent that !foo.bar.baz does not bind to the foo. We'd have to change the meaning of existing code, making it a breaking language change. For example foo.- is a proposed syntax for doing an operator tear-off. so foo.-[x] would be ambiguous.
So, not sure that feature is so great it's worth a breaking syntax change.

@munificent
Copy link
Member

For reference, Rust decided to use postfix syntax for await. I like prefix await for most cases, but it would be nice to support a postfix form in method chains too.

@boukeversteegh
Copy link

@jsanl wrote:

Maybe I'm just boring, but what about this?

expr
  ..bar() 
  ..await baz()
  ..qux();

Totally in favor of this syntax!

@lrhn
Copy link
Member Author

lrhn commented Sep 9, 2020

Using a prefix operator inline in a selector chain is an enticing idea.
It generalizes, so we could allow foo.!isEmpty or bar.-value as well. The issue with that is that it might impose on our wish to do bar.- as the minus operator tear-off.

@Sufilevy
Copy link

Is this being considered? Are there any developments on the topic?

@insinfo
Copy link

insinfo commented Nov 13, 2023

@lrhn
and I really like the option with dot await .await

@airai-ad-117
Copy link

any updates ?

whats the issue with .await syntax ?

thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem small-feature A small feature which is relatively cheap to implement.
Projects
None yet
Development

No branches or pull requests

10 participants