Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do I need to state the return type of an async function as a future object?

I was going over a lesson on async programming with Dart but for some reason I am getting kind of confused. I think I understand the concepts of how you should be using an async function when it may require some time and so instead of blocking and freezing your app you use an async function so that the next code blocks or methods are executed and when the async function is done or ready it executes. (Please let me know if my understanding is flawed)

However, I don't really get the Future<> part. I get it can be used as a return type of an async function because essentially you are saying the function returns a future object for now but let's come back to it when it's completed. But my instructor kind of confused me, sometimes she had a future as the return type and another time she didn't put it and they were both async functions. So now I'm struggling to understand when is it necessary to explicitly state the Future return type even if it is void? Also isn't just using async and wait for a function already create a future object regardless? Any clarification is greatly appreciated, thanks.

like image 285
Potato Avatar asked Jun 10 '19 04:06

Potato


People also ask

Does an async function need to return?

Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.

What is the return type of async method?

Async methods can have the following return types: Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value. void , for an event handler.

What type is used to set the Future return value and communicate that an async function is complete?

Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.

Should async function return value?

Async functions The word “async” before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically. So, async ensures that the function returns a promise, and wraps non-promises in it.


Video Answer


2 Answers

Let's consider a method gatherNewsReports() which only returns a Future<String>. The string value of the Future from gatherNewsReports. Implementation of gatherNewsReports.

// Imagine this is a slow method. Takes time to finish
Future<String> gatherNewsReports() => Future.delayed(Duration(seconds: 1), () => news);

We will go through all possible combinations of method call with Future and async. The method I am going to make is called getDailyNewsDigest

Option-1:

One definition of the method might be as with Future and async given in method call:

Future<String> getDailyNewsDigest() async {
  var str = await gatherNewsReports();
  print(str);
  return str;
}

Remember that gatherNewsReports() which returns a Future<String>. We are just returning whatever gatherNewsReports returns.

Usage:

main() async {
  await getDailyNewsDigest();
  print('call done');
}

Output:

<gathered news goes here>
call done

Comments: This seems straight forward. You just call the method and await on it. Remember we are using await keyword when calling getDailyNewsDigest from the main method. So, unless we pass 1 second, i.e, the duration of time it requires the Future to execute. If we didn't use the await keyword then the output sequence will be reversed.

Option 2

One definition of the method might be as with Future given and async NOT given in method call:

Future<String> getDailyNewsDigest() {
  var str = await gatherNewsReports();
  print(str);
  return str;
}

This is not valid because you can't call a method with await, in this case gatherNewsReports. This is invalid.

Option-3

We define the method might be with Future NOT GIVEN and async given in method call. Since the return type is going to be void we will not return anything (N.B: If we try to return anything other than a Future or a void then we get an error):

void getDailyNewsDigest() async {
  var str = await gatherNewsReports();
  print(str);
}

This is a valid method definition. Now, since the method is declared as void we can't await on the main method. The updated main method.

main() async {
  getDailyNewsDigest(); // We can't await on it since return is void
  print('call done');
}

Output:

call done
<gathered news goes here>

As you can see since the method getDailyNewsDigest is not called without await the output is reversed. We are no longer waiting for the getDailyNewsDigest to finish.

Option-4

We define the method might be with Future<Void> instead of Future<String> and async given in method call:

Future<void> getDailyNewsDigest() async {
  var str = await gatherNewsReports();
  print(str);
  return;
}

Now in our main method we can use the await keyword again for calling getDailyNewsDigest.

main() async {
  await getDailyNewsDigest(); // We can await on it since return is Future<Void> but don't care on the output since it returns nothing
  print('call done');
}

These are 4 combinations I can think of.

As for this:

But my instructor kind of confused me, sometimes she had a future as the return type and another time she didn't put it and they were both async functions.

Declaring a method with either Future means you can await on it, declaring it with void means you can't await in it. You can of course choose not to await on a Future if you don't care to do anything with the output of the Future. If you write your code in such a way that you don't want anyone to depend on the output of the method, i.e, the Future we would otherwise return from the method will be handle d by itself, all we care about is firing-it-and-continue with our work; in that case we should define our method with return type void.

like image 140
Shababb Karim Avatar answered Oct 11 '22 13:10

Shababb Karim


Yes, using the async keyword will make the function automatically return a Future.

It is always better to explicitly declare the return type of a function even for void functions, if not, the compiler will interpret the function as having a dynamic return type.

It will also help/make it easier for the reader to know the return type of the function.

Also, you need to wrap your object in a Future in an async function like so:

Future<Object> getObject() async {
  final object = await timeConsumingTask();
  return object;
}

If you write it like this without wrapping it:

Object getObject() async {
  final object = await timeConsumingTask();
  return object;
}

The compiler throws the error: Functions marked 'async' must have a return type assignable to 'Future'.

For void functions, it seems that you do not have to wrap the return type in a Future, so something like this is fine:

void doSomething() async {
  await timeConsumingTask();
  print('done');
}
like image 38
Gary AP Avatar answered Oct 11 '22 14:10

Gary AP