13

Is there a difference between an async method that returns void, and one that returns Future<void>? It seems that both are valid in Dart:

void main() async {
    await myVoid();
    await myFutureVoid();
}


void myVoid() async {
    // Do something
}


Future<void> myFutureVoid() async {
    // Do something
}

Are they identical?

If so, why is void allowed when for example int is not? The compiler says "Functions marked 'async' must have a return type assignable to 'Future'".

Magnus
  • 17,157
  • 19
  • 104
  • 189

1 Answers1

38

void f() and Future<void> f() are not identical. (The presence of the async keyword doesn't actually matter. The async keyword primarily enables the use of the await keyword in the function body.)

void f() declares a function that returns nothing. If it does asynchronous work, then that work will be "fire-and-forget": there is no opportunity for the caller of f to wait for it to finish.

In contrast, Future<void> f() declares a function that returns a Future that the caller can wait for (either by using await or by registering a Future.then() callback). There's no value returned by the asynchronous work, but callers can determine when it is finished.

Functions marked with async usually should return a Future. If you have a function that does asynchronous work that produces an actual value (such as an int), then the caller must wait for that value to be computed before it can be used. That function therefore must return a Future.

As a special case, an async function can return void instead of Future<void> to indicate that it is fire-and-forget.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • Ah, I think I got it. Just to be clear - if `myVoid` uses `await` for all it's async calls (i.e. it basically becomes a sync method), then it _is_ possible for `main` to wait for `myVoid` to finish... right? I think that's what got me confused, since I encountered such a function and couldn't figure out why it was returning `void` instead of `Future`. Especially what confused me was that IntelliJ hints _"Await only futures."_ - but it is still possible to await the function even though it returns `void`, just the same as if changing it to `Future`... – Magnus May 22 '19 at 07:45
  • While it's true that `await myVoid();` is legal, it's not the same as `await myFutureVoid();`. A caller would not be able to wait for `myVoid` to finish. There is a special case where the Dart VM/runtime recognizes that there are outstanding `Future`s and won't exit until they complete, and that might make it *seem* like `main` is waiting. However, if you did `await myVoid(); print('foo');`, you would see `foo` printed before `myVoid` completes it async work. – jamesdlin May 22 '19 at 08:17
  • Hmm, I'm not sure if I understand you correctly - if i did `await myVoid(); print('foo');` and `myVoid` is doing `await` on all its async operations, wouldn't `foo` be printed _after_ `myVoid` returns? That's the case I meant in my previous comment. I made a Gist/Dartpad sample to illustrate what I mean: https://dartpad.dartlang.org/b1acdb31305a1568cf33dc56e8df763f – Magnus May 22 '19 at 08:55
  • Huh. I stand corrected about current behavior. It's *supposed* to be an error (but isn't yet for backward compatibility reasons). You should avoid `await`ing `void`; it might break in the future (pun not intended). Also see https://github.com/dart-lang/sdk/issues/28305 and https://github.com/dart-lang/sdk/issues/33415 – jamesdlin May 22 '19 at 15:24