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

6,816

Solution 1

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');
}

Solution 2

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.

Share:
6,816
Potato
Author by

Potato

Updated on December 11, 2022

Comments

  • Potato
    Potato over 1 year

    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.

  • Potato
    Potato almost 5 years
    Okay so essentially there is no difference between using future<void> and just using void when the function doesn't return anything. Just to clarify then, i should use an async function whenever i have a time consuming task and I want the next functions in the sequence to continue while it works in the background right? Or should i also use an async function if i want to for example authenticate users using firebase so i dont want to go forward until the users are correctly authenticated? Would using an async skip and go to the next function? I've just seen those functions using this format.
  • Potato
    Potato almost 5 years
    Okay, but what do you mean when you say if you declare it with void then you cant await it. Clearly a void async function with await waits for the parts included after await to occur before continuing the function? If the function is defined with async, that means that the next function in the sequence will start working while the async function is also working correct? Can you explain more about how using async functions affects the flow of functions executed?
  • Shababb Karim
    Shababb Karim almost 5 years
    If you declare the method, suppose myMethod, as void myMethod() async, then in main method you can't do await myMethod(), you can only do myMethod(). You can of course perform await functionality from INSIDE the method since you declared it await but you can never call the method from outside with an await. So if you only call this method then the main method will flow as it is without waiting for the async function to finish.
  • Shababb Karim
    Shababb Karim almost 5 years
    declaring the method as async does not change the code flow. Only if you await on it does. Look at the outputs of option 1 and 3. The outputs are reversed, the only difference is I did not call await from the main method.
  • Gary AP
    Gary AP almost 5 years
    You want to use async/await for firebase auth to let's say go the next screen await authenticateUser(); goToNextScreen; The 'await' keyword basically means that the next line would not execute unless the time consuming task is done. This is especially useful when that next line is dependent on an object that needs to be fetched in a time consuming manner.