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.