Home > Net >  FutureOr can await void functions?
FutureOr can await void functions?

Time:04-01

As far as I understand it should not be possible to await functions like void foo() async {}, because they return no future that could be awaited. But I noticed when I assign them to a FutureOr<void> Function() field it is possible to await them. The following example prints: PRE, FUNC, POST

import 'dart:async';

void func() async {
  await Future.delayed(const Duration(seconds: 2));
  
  print('FUNC');
}

Future<void> main() async {
  final FutureOr<void> Function() t = func;
  
  print('PRE');
  await t();
  print('POST');
}

I would expect it to print: PRE, POST, FUNC

Because the function func cannot be await (because it returns void) and therefore the await t() should not wait for the completion of the func function.

I observed the same behavior with final dynamic Function() t = func;

I'm not sure if this behavior is intended or if I just don't understand void async functions?

CodePudding user response:

The await operator can be used on any object and on an expression of any type except void (and that's only because the type void is specifically disallowed in most contexts, not something special for await).

An async function always returns a future. Even if its declared return type is void. Declaring the return type as void is just a signal to users that they shouldn't expect a useful value, and it makes it harder to actually get to the value (because of the above-mentioned restrictions on using void typed expressions).

In fact, all void return-type functions return a value (unless they throw). That value is usually null, but it's not required to be. Since you can override a void foo() method with int foo() in a subclass, and assign an int Function() to a variable of type void Function(), the compiler can't actually know for sure that a function with static type void does not return anything. So, it doesn't even try to enforce it for functions that are themselves typed as returning void.

The type FutureOr<void> is a supertype of void (and of Future<void>), so a void Function() function object is assignable to the type FutureOr<void> Function().

All in all, that conspires to allow your code to work the way you see. The await t() performs an await on an expression with static type FutureOr<void> and an actual value which is a Future<void>, which was returned by a call to func. So, the await t() waits for FUNC to be printed.

CodePudding user response:

Don't use await if you want skip task. Use Future.sync() or Future.microtask() in you case. Documentation

import 'dart:async';

void func() async {
  await Future.delayed(const Duration(seconds: 2));
  
  print('FUNC');
}

Future<void> main() async {
  final FutureOr<void> Function() t = func;
  
  print('PRE');
  Future.microtask(t);
  print('POST');
}

By using await you telling to compilator that you want to wait until some task will be completed and no mater it's void or not.

  • Related