How a non async value is wrapped in a Future using await? - dart

Docs says:
In await expression, the value of expression is usually a Future; if it isn’t, then the value is automatically wrapped in a Future.
So, if I use:
void main() async {
var a = await 1;
print(a); // Prints 1
print(Future.value(1)); // Prints `Instance of _Future<int>`.
}
Using what the docs says, the first print should print Instance of _Future<int> but it prints 1. Can anyone explain what that line means by the value is automatically wrapped in a Future?

The meaning of
In await expression, the value of expression is usually a Future; if it isn’t, then the value is automatically wrapped in a Future.
is that for an expression like await 1, where the value of 1 is not a Future, the 1 is replaced by Future.value(1). The meaning of await can then be defined entirely in terms of what it does to futures, and it's clear that there will be an asynchronous delay at the await.
The await 1, aka. await Future.value(1), waits for the future to complete with the value 1, then the entire await 1 expression evaluates to that value. The await always removes "one layer of Future" from the value by waiting for the future to complete with a value, and then evaluate to to that value.
For await e, if e throws, then await e also throws immediately. The error is not wrapped up in a future. Only if e evaluates to a value, and that value does not implement Future, then the value is wrapped so that it can be awaited and unwrapped again.

The await causes the function to wait for the Future to complete. This example code:
waitFunction1() async {
var x = await 1;
print(x);
return x;
}
waitFunction2() async {
var x = await 2;
print(x);
return x;
}
main(List<String> args) async {
var x = waitFunction1();
print('1: $x');
var y = await waitFunction2();
print('2: $y');
var z = await x;
print('1: $z');
}
produces the output:
1: Instance of 'Future<dynamic>'
1
2
2: 2
1: 1
The call to waitFunction1 returns the Future. Later when it waits for it, we get the value wrapped by the Future.

Related

Dart : what happens when two or more tasks are waiting on the same Future

In Dart, when two or more tasks are waiting on the same Future, when the Future completes, do the tasks get notified/run in the order that they did the await i.e. the first to do an await is the first to run.
Is this code guaranteed to output 2
int res = 0;
Future<void> foo1 () async
{
await Future.delayed(Duration(seconds: 2));
res = 2;
}
void main() async
{
await foo1();
print(res);
}
and what about this code, slightly less obvious
int res = 0;
Future<void> foo1 () async
{
await Future.delayed(Duration(seconds: 2));
}
Future<void> foo2 (Future<void> f1) async
{
await f1;
res = 2;
}
Future<void> foo3 (Future<void> f1) async
{
await f1;
res = 3;
}
void main() async
{
res = 0;
Future<void> f1 = foo1();
foo3(f1);
foo2(f1);
await f1;
print(res);
}
There is no guarantee that the callbacks get called in the order they were added.
The dart:async library code tries to call the callbacks in that order, but it's best-effort only. There are cases, typically where one callback is added before the future is completed, and the other is added after, where it's possible to get called in a different order, because they are handled by different code paths.
It's not easy to trigger those cases, the timing has to be just right, but it is possible.
In the example here, there are three awaits on the f1 future. It's most likely that the printed value will be 2 (because nothing fancy is happening), but both 3 and 0 are allowed results.
Code printed 2.
int res = 0;
Future<void> foo1() async {
await Future.delayed(const Duration(seconds: 2));
print('foo1 method res 1: $res');
res = 2;
print('foo1 method res 2: $res');
}
void main() async {
await foo1();
print('last res: $res');
}
🧑‍💻 Code Test Output
foo1 method res 1: 0
foo1 method res 2: 2
last res: 2

Return type of void async function in Dart

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.

What's the difference between async and async* in Dart?

I am making an application using flutter framework .
During this I came across with the keywords in Dart async and async*.
Can anybody tell me what's the difference between them?
Short answer
async gives you a Future
async* gives you a Stream.
async
You add the async keyword to a function that does some work that might take a long time. It returns the result wrapped in a Future.
Future<int> doSomeLongTask() async {
await Future.delayed(const Duration(seconds: 1));
return 42;
}
You can get that result by awaiting the Future:
main() async {
int result = await doSomeLongTask();
print(result); // prints '42' after waiting 1 second
}
async*
You add the async* keyword to make a function that returns a bunch of future values one at a time. The results are wrapped in a Stream.
Stream<int> countForOneMinute() async* {
for (int i = 1; i <= 60; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
The technical term for this is asynchronous generator function. You use yield to return a value instead of return because you aren't leaving the function.
You can use await for to wait for each value emitted by the Stream.
main() async {
await for (int i in countForOneMinute()) {
print(i); // prints 1 to 60, one integer per second
}
}
Going on
Watch these videos to learn more, especially the one on Generators:
Isolates and Event Loops
Futures
Streams
async / await
Generators
Marking a function as async or async* allows it to use the async/await for a Future.
The difference between both is that async* will always return a Stream and offer some syntactical sugar to emit a value through the yield keyword.
We can therefore do the following:
Stream<int> foo() async* {
for (int i = 0; i < 42; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
This function emits a value every second, which increments every time.
Solution, Origins and Insights
This answer includes simplified and easy to understand examples
async
The async computation cannot provide a result immediately when it is started because the program may need to wait for an external response like:
Reading a file
Querying a database
Fetching data from an API
Instead of blocking all computation until the result is available, the asynchronous computation immediately returns a Future object which will eventually "complete" with the result.
Example (This type of async call can be used only without returning a response):
void main() async {
// The next line awaits 5 seconds
await Future.delayed(Duration(seconds: 5));
// Pseudo API call that takes some time
await fetchStocks();
}
Future
A Future represents a computation that doesn’t complete immediately. Whereas a normal function returns the result, an asynchronous function returns a Future, which will
eventually contain the result. The Future will tell you when the result is ready.
Future is appended when the async function returns a value
Represents the result of a single computation (in contrast to a Stream)
Example:
Future<String> fetchUserOrder() =>
// Imagine that this function is more complex and slow.
Future.delayed(
const Duration(seconds: 2),
() => 'Large Latte',
);
void main(List<String> arguments) async {
var order = await fetchUserOrder();
// App awaits 2 seconds
print('Your $order is ready');
}
Stream
A source of asynchronous data events.
A Stream provides a way to receive a sequence of events. Each event is either a data event, also called an element of the stream.
Stream is a sequence of results
From stream you get notified for results (stream elements)
async* (streams)
async* is an asynchronous generator that returns a Stream object. Made to create streams.
An example of using a stream and async*:
// Creating a new stream with async*
// Each iteration, this stream yields a number
Stream<int> createNumberStream(int number) async* {
for (int i = 1; i <= number; i++) {
yield i;
}
}
void main(List<String> arguments) {
// Calling the stream generation
var stream = createNumberStream(5);
// Listening to Stream yielding each number
stream.listen((s) => print(s));
}
Result:
1
2
3
4
5
Bonus: Transforming an Existing Stream
If you already have a stream, you can transform it to a new stream based on the original stream’s events.
Example (same code as before but with a twist):
Stream<int> createNumberStream(int number) async* {
for (int i = 1; i <= number; i++) {
yield i;
}
}
// This part is taking a previous stream through itself and outputs updated values
// This code multiplies each number from the stream
Stream<int> createNumberDoubling(Stream<int> chunk) async* {
await for (final number in chunk) {
yield number*2;
}
}
void main(List<String> arguments) {
// Here we are Transforming the first stream through createNumberDoubling stream generator
var stream = createNumberDoubling(createNumberStream(5));
stream.listen((s) => print(s));
}
Result:
2
4
6
8
10
Solution
The async and async* are close relatives, they are even from the same library dart:async
The async represent a Future and a one-time exchange while the async* represents a Stream, a stream of multiple events
Async functions execute synchronously until they reach the await keyword. Therefore, all synchronous code within an async function body executes immediately.
Future<int> foo() async {
await Future.delayed(Duration(seconds: 1));
return 0;
}
Async* is used to create a function that returns a bunch of future values one at a time. Each result is wrapped in a Stream.
Stream<int> foo() async* {
for (var i = 0; i < 10; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
async* will always return a Stream
Stream<int> mainStream(int value) async* {
for (int i = 1; i <= value; i++) {
yield i;
}
}
async returns the result wrapped in the Future. So it might take longer time. See the below example:
void main() async {
// The next line awaits 10 seconds
await Future.delayed(Duration(seconds: 10));
}

Dart await removes then?

Do await remove "then"?
Why is it that when using then in the following is causing this error:
// Error: [dart] The method 'then' isn't defined for the class 'String'. [undefined_method]
Modified code from here
import 'dart:async';
Future<void> printDailyNewsDigest() async {
var newsDigest = await gatherNewsReports();
// Error: [dart] The method 'then' isn't defined for the class 'String'. [undefined_method]
newsDigest.then(print);
// print(newsDigest);
}
main() {
printDailyNewsDigest();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
printWinningLotteryNumbers() {
print('Winning lotto numbers: [23, 63, 87, 26, 2]');
}
printWeatherForecast() {
print("Tomorrow's forecast: 70F, sunny.");
}
printBaseballScore() {
print('Baseball score: Red Sox 10, Yankees 0');
}
const news = '<gathered news goes here>';
const oneSecond = Duration(seconds: 1);
// Imagine that this function is more complex and slow. :)
Future<String> gatherNewsReports() =>
Future.delayed(oneSecond, () => news);
await doesn't "remove" then, but it allows to write async code in a more convenient syntax as with then and kind of replaces then.
await is then rewritten back to then by the compiler.
await postpones the execution of the following code until the result of the awaited async operation is completed and returns the result value.
The result value is not a Future anymore and therefore then() is not available.

Dartlang wait more than one future

I want to do something after a lot of future functions are done, but I do not know how to write the code in dart?
the code is like this:
for (var d in data) {
d.loadData().then()
}
// when all loaded
// do something here
but I don't want to wait for them one by one:
for (var d in data) {
await d.loadData(); // NOT NEED THIS
}
how to write those code in dart?
You can use Future.wait to wait for a list of futures:
import 'dart:async';
Future main() async {
var data = [];
var futures = <Future>[];
for (var d in data) {
futures.add(d.loadData());
}
await Future.wait(futures);
}
DartPad example
Existing answer gives enough information, but I want to add a note/warning.
As stated in the docs:
The value of the returned future will be a list of all the values that were produced in the order that the futures are provided by iterating futures.
So, that means that the example below will return 4 as the first element (index 0), and 2 as the second element (index 1).
import 'dart:async';
Future main() async {
print('start');
List<int> li = await Future.wait<int>([
fetchLong(), // longer (which gives 4) is first
fetchShort(), // shorter (which gives 2) is second
]);
print('results: ${li[0]} ${li[1]}'); // results: 4 2
}
Future<int> fetchShort() {
return Future.delayed(Duration(seconds: 3), () {
print('Short!');
return 2;
});
}
Future<int> fetchLong() {
return Future.delayed(Duration(seconds: 5), () {
print('Long!');
return 4;
});
}
If you want to wait for multiple futures of different types and also support null-safety then you can add a helper function similar to the following.
import 'package:tuple/tuple.dart';
Future<Tuple2<T1, T2>> waitConcurrently<T1, T2>(
Future<T1> future1, Future<T2> future2) async {
late T1 result1;
late T2 result2;
await Future.wait([
future1.then((value) => result1 = value),
future2.then((value) => result2 = value)
]);
return Future.value(Tuple2(result1, result2));
}
In order for this to work you need tuples.
At the moment Dart does not provide tuples natively, but there is a package from Google which does: https://pub.dev/packages/tuple
In addition, I'd like to supplement Günter Zöchbauer's answer with FutureOr variant. You'll need to convert your FutureOr<T> variable to Future<T> first and then call wait:
Future.wait(list.map((x) async => x))

Resources