Article on Async-Await

461 views
Skip to first unread message

Gilad Bracha

unread,
Oct 24, 2014, 6:00:28 PM10/24/14
to General Dart Discussion
A short article about async-await in Dart is on our web site:



Peter Jakobs

unread,
Oct 26, 2014, 5:48:11 AM10/26/14
to mi...@dartlang.org
I thought about how I can use await, but I would need a way to "silently" cancel await/await* (for example when an object gets removed from a scene I want all await statements to stop awaiting) and complete the await statements synchronous inside an gameloop, is that possible?

Cogman

unread,
Oct 26, 2014, 8:52:19 AM10/26/14
to mi...@dartlang.org
In the last game loop example, why is main marked as async? Is it the case that any function using await must be async?

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

William Hesse

unread,
Oct 26, 2014, 9:49:26 AM10/26/14
to General Dart Discussion
Yes, the body of main is marked async because it uses await.  Marking a function's body async means that it is compiled with support for await (it supports await), and also that the function therefore returns a future (because a function using await must be doing something asynchronously, and therefore it can't return its result immediately).

If we declared a return type for main, it would have to be declared to return a Future.

The caller of a function whose body is marked async doesn't know that it is any different from calling any other async function that returns a future.  Marking the function body as async is just affecting the implementation of that function, as if we could mark a function body as "C" and write it in C instead.

--
William Hesse

Justin

unread,
Oct 27, 2014, 11:32:46 AM10/27/14
to mi...@dartlang.org
Is the Await syntax (which I prefer) intended to replace the .then()=> syntax in some instances, in all instances, or is it intended for an entirely different use-case? For instance (using package http:dart) I have:-

  var client = new http.Client();
      url,
      body: json_request)
    .then((response) => print(response.body))

Should this now be something like

print ((await client.post(url, body: json_request)).body)

?

Bob Nystrom

unread,
Oct 27, 2014, 12:15:05 PM10/27/14
to General Dart Discussion
Yes.

It should replace .then() in almost all cases. The main place where you'll still use raw futures is when you need a method that has a synchronous prelude followed by asynchrony. For example:

Future _pendingLoad;

Future load() {
  // If we're already in-progress, use the same future.
  if (_pendingLoad != null) return _pendingLoad;

  _pendingLoad = ...;
}

Here, it's important that the first line executes synchronously, otherwise you can accidentally double-load in some cases. Since async methods always bounce to the event loop before starting their body, this function cannot be expressed using it.

There are probably other cases where you're doing raw or unusual concurrency patterns that don't map well to await, but the above is the main case I know of.

Cheers!

- bob

Lasse R.H. Nielsen

unread,
Oct 27, 2014, 12:23:34 PM10/27/14
to mi...@dartlang.org

It *could* be written like that, but whether it *should* is entirely up to the author. There are things you can do with futures that has no corresponding syntax, but most of the common users will probably be doable, and more readable, with the new syntax.

Personally I'll likely use temporary variables for await expressions:

var response = await client.post(...);
print (response.body);

/L

Lasse R.H. Nielsen

unread,
Oct 27, 2014, 12:28:08 PM10/27/14
to mi...@dartlang.org

Ob-pedantry: The example actually works even if the initial part isn't synchronous. The first function body to be executed will set the pending future, and late bodies will return it, no matter which one was actually called first. The only difference is that you don't return an identical future, just an equivalent one.

Bob Nystrom

unread,
Oct 27, 2014, 12:45:16 PM10/27/14
to General Dart Discussion

On Mon, Oct 27, 2014 at 9:28 AM, 'Lasse R.H. Nielsen' via Dart Misc <mi...@dartlang.org> wrote:
Ob-pedantry: The example actually works even if the initial part isn't synchronous. The first function body to be executed will set the pending future, and late bodies will return it, no matter which one was actually called first. The only difference is that you don't return an identical future, just an equivalent one.

I think it depends on what's in the "..." part. Consider:

Future _pendingLoad;

Future load() async {
  // If we're already in-progress, use the same future.
  if (_pendingLoad != null) return _pendingLoad;

  return _pendingLoad = foo(await bar());
}

Here, it's possible to have this sequence of events:
  1. The first call to load() bounces to the event loop.
  2. Then the body starts executing until it hits await bar() at which point it suspends.
  3. The second call to load() bounces to the event loop.
  4. bar() is still waiting so the second call starts executing the body and also reaches await bar() (which may return an entirely unrelated future this time).
Then those two awaits complete in some order. Both calls proceed and each sets _pendingLoad to a different future, the second one overwriting the first.

- bob

Lasse R.H. Nielsen

unread,
Oct 27, 2014, 1:11:37 PM10/27/14
to mi...@dartlang.org
Ack, yes, I see. Had the body been:
  _pendingFuture = bar.then(foo);
it would execute immediately, but if you put the await in the middle, you delay the assignment.

This is probably also a good suggestion for a rule: don't mix futures as values and async/await syntax - better to use one or the other, otherwise everybody will get confused :).
 
/L

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.



--
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84

Richard Lincoln

unread,
Oct 27, 2014, 2:04:21 PM10/27/14
to mi...@dartlang.org
Would it be possible to kick off a new build of the dev channel?  Async-await support was added to the Dart Editor in rev 41297, but currently the last dev build was based on rev 41145.

I couldn't write Hello World without editor support.

Kevin Millikin

unread,
Oct 27, 2014, 3:08:16 PM10/27/14
to mi...@dartlang.org
To add to what Bob and Lasse already wrote:

await replaces almost all uses of .then.  It also replaces uses of .catchError and .whenComplete, by nesting await inside try/catch or try/finally.  This is a big advantage because it's easier to see the nesting of catch or finally handlers, and more difficult to make some of the classic mistakes of forgetting to install a catchError handler in time.  It also replace recursive .then handlers with loops, including break and continue.  It also replace uses of new Future.value or new Future.error (in the case that the subexpression is respectively, a non-future value or throws).

In short, you can use all the control structures of the language, instead of just function calls.

--

Kevin Millikin

unread,
Oct 27, 2014, 3:16:54 PM10/27/14
to mi...@dartlang.org
Bob, out of curiosity, how would you write this with the dart:async API?  The assignment to _pendingLoad can't come in bar's then handler anyway, or can it?

Bob Nystrom

unread,
Oct 27, 2014, 4:12:54 PM10/27/14
to General Dart Discussion

On Mon, Oct 27, 2014 at 12:16 PM, 'Kevin Millikin' via Dart Misc <mi...@dartlang.org> wrote:
Bob, out of curiosity, how would you write this with the dart:async API?  The assignment to _pendingLoad can't come in bar's then handler anyway, or can it?

I believe just writing it like this will do the right thing:

Future _pendingLoad;

Future load() {
  // If we're already in-progress, use the same future.
  if (_pendingLoad != null) return _pendingLoad;

  return _pendingLoad = bar().then(foo);
}

- bob

Kevin Millikin

unread,
Oct 28, 2014, 2:31:00 AM10/28/14
to mi...@dartlang.org
So I wonder if the idiom might become:

Future _pendingLoad;

Future load() {
  // If we're already in-progress, use the same future.
  if (_pendingLoad != null) return _pendingLoad;

  Future barThenFoo() async => foo(await bar());

  return _pendingLoad = barThenFoo();
}

But obviously you wouldn't bother unless the example was more complicated.  It does suggest a missing feature.  Something like an async block.  But with a value.  Async literals!

Justin

unread,
Oct 28, 2014, 3:49:13 AM10/28/14
to mi...@dartlang.org
On Monday, October 27, 2014 6:04:21 PM UTC, Richard Lincoln wrote:
Would it be possible to kick off a new build of the dev channel?  Async-await support was added to the Dart Editor in rev 41297, but currently the last dev build was based on rev 41145.

Has this now been done? I see there is a new build (28 Oct). When will this be hitting STABLE? I am a complete novice on Dart. I don't really have any business being on the dev channel, but my project is heavily asynchronous. It seems silly to write it in a more difficult, and now deprecated, syntax.

Matthew Butler

unread,
Oct 28, 2014, 8:44:25 AM10/28/14
to mi...@dartlang.org
Futures are not depreciated. They will continue to exist and continue to be used. It's a personal preference. Secondly the async/await work is only just begining and currently incomplete.  Per the caveat in the article:
The features described in this article are still under development. Not all the parts of the system necessarily comply with the spec.
...
Overall, you should regard this article as a heads up for early adopters. 

 So per your statement, if you don't feel comfortable on the dev channel, you probably shouldn't feel comfortable with using the current implementation of async/await.

Finally, Dart is currently using channel releases. For stable branch they aim for a new release approximately every six weeks. See more on the initial announcement of channels here
https://groups.google.com/a/dartlang.org/forum/#!topic/announce/UXRMVmX_6EQ

:-) Matt

jm

unread,
Oct 28, 2014, 1:55:16 PM10/28/14
to mi...@dartlang.org


2014/10/28 20:00:28 UTC-2, Gilad:
A short article about async-await in Dart is on our web site:




What I naively don't understand, is WHY we need async in the first place. Can't the system infer that we are using an async function, greedily continue processing the remainder of the body, to only await when actually blocking? To then continue wherever a value becomes available (in this body or another) and evaluating whatever is now possible to evaluate.

In other words, we don't need to await explicitly. We know which functions are async, and we know that, when we use their values, we must await.

If we want to work with the future instead of the value of the result, just declare the type of the receiver accordingly.

In linear bodies the system can substitute the sync equivalents of async functions.

As flow is now non-linear by default, the "compiler" must factor out different paths (no need for perfection), instead of us doing the same. Seems doable. Error handling may even benefit from writing in a linear style.

Seems to me this would laud extremely desirable semantics. So what's the 800 pound gorilla in the room everyone seems to be seeing?





 

Gilad Bracha

unread,
Oct 28, 2014, 3:12:15 PM10/28/14
to mi...@dartlang.org
I can't really tell exactly what you are suggesting: eliminating async only or both async and await. 

Some things to remember:

Things like return statements behave differently in an async function (they wrap the result in a future) so you need to know that a function is async at compile time.  You cannot base any of these decisions on type annotations because Dart is optionally typed.
You could infer that a function is async from the presence of an await (so much for eliminating await). This would be an incompatible change because await is not a keyword in earlier versions of  Dart. Besides, async serves as  mandatory documentation (unlike types). You can tell if something is async at a glance, without examining its internals. It is also a useful cross-check (don't wait by accident).  Additionally unlike the C# semantics, we know what functions are asynchronous and we know (reliably) where they suspend.




--

曹忠

unread,
Oct 28, 2014, 3:22:48 PM10/28/14
to
Great works! just like python yield and other lang async pave.
What sdk version can try this feature?

在 2014年10月25日星期六UTC+8上午6时00分28秒,Gilad写道:

Jan Meyer

unread,
Oct 28, 2014, 4:05:35 PM10/28/14
to mi...@dartlang.org
On 10/28/14, 'Gilad Bracha' via Dart Misc <mi...@dartlang.org> wrote:
> I can't really tell exactly what you are suggesting: eliminating async only
> or both async and await.
>

TLDR: they should mostly be optional.

when I do something async, in a seemingly stupidly sync way, like:

txt1 = file1.getContents()
txt1 = txt2 + '1234'
file1.setContents(txt1)

txt2 = file2.getContents()
txt2 = txt2 + '1234'
file2.setContents(txt2)

file3.setContents(txt1 + txt2)

txt isn't available until file.getContents() is done. we know that and
the function is therefore marked as async and the first assignment is
SIMILAR to:

txt1 = await file1.getContents();

but this would make the flow sync. which is not what we want. we want
to suspend on

txt1 = file1.getContents()

then skip the statements that involve txt1 and procede to

txt2 = file2.getContents()

to only then stall.

when txt1 comes available the expressions that depend on its result
are evaluated. likewise for txt2. this includes the final statement,
which waits for both to complete. no need to mark things up with async
and await, that will only be necessary to enforce a particular order,
in which case the futures become explicit (and typing is no longer
optional :-)

behind the scenes this is all async, except that the programmer doesnt
have to do anything for the default case. it just runs as if it were
synchronous. the difference is what *we* read into the code, its
semantics. but it seems there is no need for the machine to literally
obey "our" semantics. it can reshuffle operations as it sees fit, just
like SQL does, and just like a compiler already does, and probably
better so.

Bob Nystrom

unread,
Oct 28, 2014, 4:18:52 PM10/28/14
to General Dart Discussion

On Tue, Oct 28, 2014 at 10:55 AM, jm <janm...@gmail.com> wrote:
We know which functions are async, and we know that, when we use their values, we must await.

Unfortunately, we don't know which functions are async. Consider:

identity(value) => value;

If value is a Future it is, if not, it's not.

- bob

Gilad Bracha

unread,
Oct 28, 2014, 4:22:14 PM10/28/14
to mi...@dartlang.org


As Bob said - we don't know what you think we know. You could get an effect similar to what you describe with promise chaining, but you need non-local returns to make it work with control flow. 

Jan Meyer

unread,
Oct 28, 2014, 6:11:17 PM10/28/14
to mi...@dartlang.org
On 10/28/14, 'Gilad Bracha' via Dart Misc <mi...@dartlang.org> wrote:
>
> As Bob said - we don't know what you think we know.
>

what modesty! :D


maybe provide a keyword (future) at the call site:

future var txt1 = file1.getContents()

this would reorder evaluation of dependent expressions until txt1 is
available, otherwise txt1 will be awaited for if it turns out to be
async, if not an outright error.

the key concept is that awaiting occurs by using the value.

Bob Nystrom

unread,
Oct 28, 2014, 6:19:37 PM10/28/14
to General Dart Discussion

On Tue, Oct 28, 2014 at 3:11 PM, Jan Meyer <janm...@gmail.com> wrote:
maybe provide a keyword (future) at the call site:

  future var txt1 = file1.getContents()

this would reorder evaluation of dependent expressions until txt1 is
available, otherwise txt1 will be awaited for if it turns out to be
async, if not an outright error.

Consider:

future var a = file.getContents();
var b = "a normal value";
var c = todayIsTuesday ? a : b;
// do something with c...

How would you compile this to (efficient) JavaScript?

We really can't associate asynchronous transforms with values, because values are only known at runtime. Dart doesn't have a sound type system that would let us determine statically which values are synchronous and which aren't.

Cheers,

- bob

Jan Meyer

unread,
Oct 28, 2014, 8:31:33 PM10/28/14
to mi...@dartlang.org
On 10/28/14, 'Bob Nystrom' via Dart Misc <mi...@dartlang.org> wrote:
> On Tue, Oct 28, 2014 at 3:11 PM, Jan Meyer <janm...@gmail.com> wrote:
>
>> maybe provide a keyword (future) at the call site:
>>
>> future var txt1 = file1.getContents()
>>
>> this would reorder evaluation of dependent expressions until txt1 is
>> available, otherwise txt1 will be awaited for if it turns out to be
>> async, if not an outright error.
>>
>
> Consider:
>
> future var a = file.getContents();
> var b = "a normal value";
> var c = todayIsTuesday ? a : b;
> // do something with c...
>
> How would you compile this to (efficient) JavaScript?
>

with todayIsTuesday right at the top and <a> being assigned and
materializing in its own branch, so in one branch <c> is a future (up
to the point where the value is needed), and in the other it isn't.

the point of your question escapes me.

> We really can't associate asynchronous transforms with values, because
> values are only known at runtime. Dart doesn't have a sound type system
> that would let us determine statically which values are synchronous and
> which aren't.
>

can it be sound in just this (very limited) sense?

you are telling me this is a catch 22. the Dart VM could be made to be
sufficiently capable of inferring asyncness at runtime, but the JS VM
would not have this capability, putting the burden on dart2js, which
is a compiler which doesn't have access to runtime info, and best
works with static type analysis, but Dart has no sound type system.
etc.

so you tell me :)

what if we can limit the scope of the problem to a single function?
would that make the problem tractable?

I just know "automatic flow management" is at least as desirable as
"automatic memory management", and as one of the benefits is trivial
performance, some performance may be sacrificed getting there. then,
even when best case performance is somewhat comprimised, the feature
enables fluidity and a whole new way of programming.

it may even turnout to have a similar implementation to the GC,
marking and sweeping expressions already evaluated.

Richard Lincoln

unread,
Nov 3, 2014, 10:24:42 AM11/3/14
to mi...@dartlang.org
I have been trying out async/await support in:

Dart Editor version 1.8.0.dev_02_00 (DEV)
Dart SDK version 1.8.0-dev.2.0

I have selected "Enable Async Support" and it works fine for a command-line app.  However, if I "Run in Dartium" then I get the error:

"use flag --enable-async to enable async/await features"

How do I pass this flag to the VM in Dartium?  Should this be handled for me by Dart Editor?

Richard

Filipe Morgado

unread,
Nov 3, 2014, 10:56:18 AM11/3/14
to mi...@dartlang.org
In the editor, under the menu item [Run -> Manage Launched], you can enter custom VM flags in the [VM Arguments] field ... I think.

William Hesse

unread,
Nov 3, 2014, 11:04:49 AM11/3/14
to General Dart Discussion
In response to JM:

Futures already support writing a block of mixed sync and async code in which all operations run as soon as their inputs are ready, but the new "await" syntax does not support that because it makes it so unpredictable in which order the lines of code run.  Error handling also gets more complicated.

But if you want a data-flow type of programming, in which all functions run as soon as their inputs are ready, then it can be done by turning:
async {
  var a = await asyncA();
  var b = syncB(a);

  var c = asyncC();
  var d = syncD(await c);

  var e = asyncE( a, await c, d);
  return syncF(b, d, await e);
}

into

{
   var a = asyncA();
   var b = a.then((av) => syncB(av));

   var c = asyncC();
   var d = c.then((cv) => syncD(cv));

   var e = a.then((av) => c.then((cv) => d.then((dv) => asyncE(av, cv, dv))));
   return b.then((bv) => d.then((dv) => e.then((ev) => syncF(bv, dv, ev))));
}

in which everything is a future.  Futures can be waited on (have ".then" applied) more than once, and all callbacks will be run when the future completes.  This can be much simplified by adding a library "lift" that transforms all functions into functions that operate on futures and return on futures, and the code is then:

{
  var a = asyncA();
  var b = lift1(syncB)(a);

  var c = asyncC();
  var d = lift1(syncD)(c);

  var e = lift3(asyncE)(a, c, d);
  return lift3(syncF)(b, d, e);
},

where lift1(g) => (a) { if (a is Future) { return a.then((av) => g(av); } else { return g(a); } }

But this type of data-driven asynchronous control flow is a special optimization, and I think most programmers would rather control what is running simultaneously more explicitly.

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.



--
William Hesse

Richard Lincoln

unread,
Nov 3, 2014, 12:19:02 PM11/3/14
to mi...@dartlang.org
Thank you for your reply.  I only see the "VM arguments" option for a command-line launch configuration.  A Dartium launch configuration provides a "Browser arguments:" field.  Using "--incognito" works nicely, but I don't know if it can be used to pass Dart VM arguments.

$ ~/opt/dart_dev/dart/chromium/chrome --help
No manual entry for chrome

Richard Lincoln

unread,
Nov 3, 2014, 12:53:08 PM11/3/14
to mi...@dartlang.org
As a temporary fix it is possible to start Dartium with DART_FLAGS="--enable-async".  E.g.

DART_FLAGS="--enable-async" ~/opt/dart_dev/dart/chromium/chrome --remote-debugging-port=35381 --user-data-dir=/home/rwl/.dartium --enable-experimental-web-platform-features --enable-html-imports --no-first-run --no-default-browser-check --no-process-singleton-dialog --flag-switches-begin --flag-switches-end chrome://version/

Ultimately, I think something needs to be added to BrowserManager.startNewBrowserProcess()

https://github.com/dart-lang/bleeding_edge/blob/d2491854153aa0a5b33ef7916e77186c55de17a8/dart/editor/tools/plugins/com.google.dart.tools.debug.core/src/com/google/dart/tools/debug/core/util/BrowserManager.java#L661
Reply all
Reply to author
Forward
0 new messages