I've been at this for hours studying the Futures and Error Handling section on the Dart page without any luck. Can anyone explain why the code below does not print All good?
import 'dart:async';
main() async {
try {
await func1();
} catch (e) {
print('All good');
}
}
Future func1() {
var completer = new Completer();
func2().catchError(() => completer.completeError('Noo'));
return completer.future;
}
Future func2() {
var completer = new Completer();
completer.completeError('Noo');
return completer.future;
}
In func1 the function used as catchError parameter must be a subtype of type (dynamic) => dynamic regarding the error:
Unhandled exception:
type '() => dynamic' is not a subtype of type '(dynamic) => dynamic' of 'f'.
Thus you should use:
Future func1() {
var completer = new Completer();
func2().catchError((e) => completer.completeError('Noo'));
return completer.future;
}
You don't get any analyzer error because the parameter is typed with Function. You can file an issue to know why the type is not a more specific type matching (dynamic)=>dynamic
Related
I have:
Future<bool> foo() async => true;
This is allowed:
Future<void> bar() {
return foo(); // Works
}
but this is not:
Future<void> baz() async {
return foo(); // Error
}
In both bar and baz I'm returning a Future<bool>, but why first works but second fails?
Note: This question isn't about HOW to make it work but rather WHY one works and the other doesn't.
Dart has special rules for void returning functions: You are not allowed to return a value because it's declared as not returning any value, so actually trying to return a value is probably a mistake.
The same happens without Future:
void qux() {
return true; // Error, can't return value from void function
}
gives the error
A value of type 'bool' can't be returned from the function 'qux' because it has a return type of 'void'.
You are allowed to have return e; statements, but only if the type of e is void, Null or dynamic. (And you shouldn't even do that, those are just allowed in order to make existing code work.)
(A => e body is always allowed, because people like to use it as a shorthand for just { e; }, mainly because the formatter keeps it on one line. I still recommend using { e; } as body of a void function.)
Generalizing that to async functions with void future return types,
you are not allowed to return an actual value from Future<void> ... async function. So, the only things you are allowed to return are void, dynamic, Null, Future<void>, Future<dynamic>, and Future<Null>.
A Future<bool> is neither of those.
What you should write instead is:
Future<void> baz() async {
await foo();
}
As I have observed when I am running the same code
Future<bool> foo() async => true;
Future<void> bar() {
return foo(); // Works
}
Future<void> baz() async {
// return foo(); // Error
}
void main() {
print("direct =====${foo()}");
print("bar==========${bar()}");
print("bazz========${baz()}");
}
The response is
direct =====Instance of '_Future<bool>'
bar==========Instance of '_Future<bool>'
bazz========Instance of '_Future<void>'
this signifies that when the async keyword is not present it takes the return type of the returning value.
But of the bazz function it gives a quick fix to make the function
Future<Future<bool>>
so when async is added the function return type is taken as the main type
Future<bool> foo() async => true;
First Case
Future<void> bar() {
return foo(); // Works
}
For the code above, the return of Future<void> bar() can return foo(), because the bar() not return directly the value of foo(), so the bar() can deal with foo() without no problem.
But, in the second case:
Future<void> baz() async {
return foo(); // Error
}
The code above is return directly the generic type of foo() because the function of baz() include async tag, so it will be trouble with the baz() as Future<void>, which is we know that foo() as Future<bool>
Why is the follow code valid? I thought there should be compile-time errors. I thought the return in the body return an int(value 1). If not, it must be returning a Future, which does not comply to the return type either. What has happened with the await?
void longRun() async {
return await Future.delayed(
Duration(seconds: 3),
()=>1,
);
}
If I assign the await part to a variable, like the following, the compiler starts to complain, which is obvious and easy to understand. But why doesn't the code above complain?
void longRun() async {
var foo = await Future.delayed(
Duration(seconds: 3),
()=>1,
);
return foo;
}
Keep studying I've found more confusing thing: all the following versions work. They seem identical, wired.
version1:
void longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
version2:
Future<void> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
version3:
Future<int> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
version4:
Future longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
version5:
Future longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
version6:
void longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
This is mostly about the behavior of =>, not about await. Normally () => 1 can be thought of as shorthand for () { return 1; }, but that's actually an oversimplification.
=> is allowed for void functions as a convenience so that people can write things like:
bool functionWithSideEffect() {
print('Some side effect');
return true;
}
void foo() => functionWithSideEffect();
int _someValue = 0;
set someValue(int value) => _someValue = value;
even though these aren't legal:
var foo() {
// error: A value of type 'bool' can't be returned from the function 'foo'
// because it has a return type of 'void'.
return functionWithSideEffect();
}
set someValue(int value) {
// error: A value of type 'int' can't be returned from the function
// 'someValue' because it has a return type of 'void'.
return _someValue = value;
}
The crux of your confusion is that () => 1 either could be int Function() or void Function(), and type inference picks different things given different constraints.
When you do:
void longRun() async {
return await Future.delayed(
Duration(seconds: 3),
()=>1,
);
}
then type inference works outside-in, propagating the void return type of longRun through the unconstrained, returned expression. The Future.delayed call is inferred to be Future<void>.delayed and the () => 1 callback is inferred to be void Function(). (Arguably a void async function returning Future<void> could be treated as error.)
In contrast, when you do:
void longRun() async {
var foo = await Future.delayed(
Duration(seconds: 3),
()=>1,
);
return foo;
}
now type inference runs in the other direction (inside-out): foo has no explicit type, so it does not constrain the right-hand-side. Therefore () => 1 is instead assumed to be int Function(), which causes Future.delayed to be inferred to be Future<int>.delayed and foo to be inferred as an int. Since foo is an int, attempting to return it from a function declared to return void is an error.
version2:
Future<void> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
You've changed longRun's return type from void to Future<void>. async functions usually should return a Future but may also return void to be fire-and-forget. The only difference from version 1 is that callers can now wait (fire a callback) when longRun completes. () => 1 is still inferred to be void Function().
version3:
Future<int> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
Same as version2 except longRun returns Future<int> instead of Future<void>. Now () => 1 is inferred to be int Function().
version4:
Future longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
longRun's return type is now Future, which means Future<dynamic>. () => 1 is inferred to be dynamic Function().
version5:
Future longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
Same as version4 except there is no explicit return statement. Now the Future.delayed expression is no longer constrained by longRun's return type, and inference will flow inside-out; () => 1 is assumed to be int Function().
version6:
void longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
Same as version5 except that longRun returns void and is a fire-and-forget function. Callers cannot be notified when longRun completes.
(Note that in the above, when I write () => 1 is inferred to be int Function() or void Function(), it really should be FutureOr<int> Function() or FutureOr<void> Function(), but that's not the important part.)
Edit:
Pre-emptively addressing some potential follow-up questions:
Why is:
void longRun() async {
int f() {
return 1;
}
return await Future<void>.delayed(
Duration(seconds: 3),
f,
);
}
okay, but:
void longRun() async {
return await Future<void>.delayed(
Duration(seconds: 3),
// info: Don't assign to void.
() {
return 1;
},
);
}
generates an analysis complaint? Both versions are legal because substituting a Future<U> for a Future<T> is legal when U is a subtype of T. When T is void, U can be anything; the value can just be ignored. (In Dart, partly for historical reasons when it didn't always have a void type, void actually means that the value cannot be used and not that there is no value. void x = 42; is legal, but attempting to read the value of x would be an error. This is why the "Don't assign to void" analysis complaint isn't categorized as an error.)
In the second version that uses an anonymous function, the tighter locality of the return statement allows the analyzer to perform more extensive checks.
In Dart, if you have an async function that doesn't return anything, should it return Future<void> or simply void? Both seem to work, but why?
void foo() async {
print('foo');
}
Future<void> bar() async {
print('bar');
}
void main() async {
await foo();
await bar();
print('baz');
}
Compiles with no errors or warnings and prints
foo
bar
baz
In your code, both functions foo() and bar() are not returning anything so any function return type is valid for both functions eg:
void/T/Future<T>... foo() async {
print('foo');
}
Future<void>/T/Future<T>... bar() async {
print('bar');
}
and here,
await foo();
await bar();
await just waits till the execution of these async functions is complete. As there is no return type, await has no purpose here(redundant) so this is and should not be a compilation error.
The difference is that Future<void> gives you information of the execution of the function like when the execution is complete and it also allows you to specify what to do when the function is executed by using bar().then(...) and bar().whenComplete(...).
While foo() function return void and void does not hold as such any info like Future<void>. If you try to await bar() it will convert that Future object from Future<void> to void.
Future is just a container, with await returns the values once the async "tasks" are completed. Without await, Future objects give you information about the execution of the function from which they are returning.
Thanks to the other answers - they were a little unclear to me so I'm just going to add some clarifications after experimenting on DartPad:
It is never an error or even a warning! to not return a value from a function, irrespective of the return type. This madness is presumably inherited from Javascript.
If you don't return from a function it implicitly returns null. Except in these cases:
If the return type is void, it does not return a value (and using the result of the expression is a compiler error).
If the function is async:
If the return type is void, you cannot use the result of the function, however you can still await it but you cannot use the result of the await expression, or use any methods of Future.
If the return type is Future<void> it returns an instance of Future<void>. You can await it, and call methods of Future, e.g. .then((void v) { ... });. However you cannot use the result of await (because it is void).
If the return type is Future<T> it returns an instance of Future<T> that resolves to null.
So basically, if you want to allow callers to use Future methods, you need to annotate the return type as Future<void>. If you merely want them to be able to await the function, you only need void. However since you probably don't know in advance I suspect it is a good idea to always use Future<void>.
Here's an example that demonstrates the possibilities:
// Compilation error - functions marked async must have a
// return type assignable to 'Future'
// int int_async() async {
// }
void void_async() async {
}
Future<void> future_void_async() async {
}
Future<int> future_int_async() async {
}
int int_sync() {
}
void void_sync() {
}
Future<void> future_void_sync() {
}
Future<int> future_int_sync() {
}
void main() async {
// print('${void_async()}'); // Compilation error - expression has type void.
print('future_void_async: ${future_void_async()}');
print('future_int_async: ${future_int_async()}');
// print('${await future_void_async()}'); // Compilation error.
await future_void_async();
future_void_async().then((void v) {
print('ok');
});
await void_async();
// void_async().then((void v) { // Compilation error.
// print('ok');
// });
print('await future_int_async: ${await future_int_async()}');
print('int_sync: ${int_sync()}');
// print('${void_sync()}'); // Compilation error - expression has type void
print('future_void_sync: ${future_void_sync()}');
print('future_int_sync: ${future_int_sync()}');
}
It prints
future_void_async: Instance of '_Future<void>'
future_int_async: Instance of '_Future<int>'
ok
await future_int_async: null
int_sync: null
future_void_sync: null
future_int_sync: null
A Future is simply a representation of an Object that hasn't completed the underlying function, and thus is a "promise" for later use. When you use Future<void>, there's no Object to return anyways, so it doesn't matter whether you use void or Future<void>. (The function doesn't return anything, so the return type is a placeholder anyways.)
However...
Future<void> can be used for listeners, and to check when things are complete, as can every Future. This means that you can use Future's listeners to check for completion or errors in running your Future<void> async function, but not your void async function. Thus, in some cases, it's better to give Future<void> than void as the return type.
Consider this example:
Future<int> doAsyncThing() => new Future.value(42);
usingAsync() async => doAsyncThing();
main() {
var thing = usingAsync();
// what is the runtimeType of thing ?
}
What is the runtimeType of the object returned by usingAsync() ? Would it be Future<Future<int>> or Future<int> or something else ?
The return type of usingAsync() is technically dynamic because there is no return type annotation given for usingAsync(). Omitting a return type annotation is the same as using dynamic for the return type annotation.
The runtimeType of the object returned by usingAsync() is Future<dynamic>. Functions marked with async simply always return a Future<dynamic> object.
When the Future from usingAsync() completes, it "flattens" its contained Future, and completes with an int.
import 'dart:async';
Future<int> doAsyncThing() => new Future.value(42);
usingAsync() async => doAsyncThing();
main() {
var thing = usingAsync();
// what is the runtimeType of thing ?
print(thing.runtimeType); // Future
thing.then((value) {
print(value); // 42
print(value.runtimeType); // int
});
}
The author of the code sample in the original question probably wants to write:
Future<int> usingAsync() async => await doAsyncThing();
Or, even cleaner:
Future<int> usingAsync() => doAsyncThing();
That is, if your function returns a Future, you might not need to mark your function as async. Just return the Future.
See it in action: https://dartpad.dartlang.org/73fed0857efab196e3f9
How I can return Future value from Future object?
This code does not work.
import 'dart:async';
void main() {
var temp = foo();
temp.then((Future<int> future) {
future.then((int result) {
print(result);
});
});
}
Future<Future<int>> foo() {
return new Future<Future<int>>(() {
return new Future<int>(() => 5);
});
}
How to prevent unnecessary unwrapping?
In this case in async library 'Future' declared as generic class.
abstract class Future<T> {
}
If I create expression as the following
new Future<Future<int>>();
Then with type T specified as Future<int> which result expected from generic class Future?
I thing that result must be as specified in type argument T.
I.e. Future<int>.
But result is not as expected.
There is no information found about this abnormal behavior on Dart API site.
If this is a "feature" (but I think that abnormal behavior wrongly to call "feature') then why it not documented in Dart API?
How can be explained this discrepancy?
Why this code not generated errors and warnings?
Another IDENTICAL example but w/o using Future.
void main() {
var temp = foo();
temp.baz((Foo<int> foo) {
foo.baz((int result) {
print(result);
});
});
}
Foo<Foo<int>> foo() {
return new Foo<Foo<int>>(() {
return new Foo<int>(() => 5);
});
}
If in this case result will be as when using Future (i.e. unexpected) then how we can call this code?
Normal or abnormal?
Or maybe the Future in Dart some special (magic)?
Look at the api documentation
http://api.dartlang.org/docs/releases/latest/dart_async/Future.html
It says there:
If the returned value is itself a Future, completion of the created future will wait until
the returned future completes, and will then complete with the same result.
I guess that means you can't return a Future from a Future.
But you could return a list of futures.
void main() {
var temp = foo();
temp.then((List<Future<int>> list) {
list[0].then((int result) {
print(result);
});
});
}
Future<List<Future<int>>> foo() {
return new Future<List<Future<int>>>(() {
return [new Future<int>(() => 5)];
});
}
There is no need for any of that extra wrapping. According to the Future documentation:
If the returned value is itself a [Future], completion of the created
future will wait until the returned future completes, and will then
complete with the same result.
This means you can rewrite your code as:
import 'dart:async';
void main() {
var temp = foo();
temp.then((int result) {
print(result);
});
}
Future<int> foo() {
return new Future<int>(() {
return new Future<int>(() => 5);
});
}
This is a lot cleaner to work with and provides the expected result.