Future<void> async vs simply void async in Dart

1,195

Solution 1

With your edit, your question makes more sense. Your question is really about principle vs. practice.

In principle, a function that returns void is different from a function that returns Future<void>. One conceptually represents something that does not return anything, and the other represents an asynchronous computation that can fire callbacks when it completes.

In principle, you should never attempt to use the value returned from a void function. It doesn't make sense. If you run the Dart analyzer against code that does await nonFutureVoid(); you'll get a warning if the await_only_futures lint is enabled.

In practice, there are cases where attempting to use a void return value happens to not generate an error. Those are quirks in the language (or bugs in the implementation); you should not rely on them. (Dart didn't originally have a void return type. When it was added later, it wasn't implemented to mean "no value" but instead to mean "a value that you aren't allowed to use". See Dart 2: Legacy of the void. Normally that subtle difference shouldn't matter.)

Being able to do await nonFutureVoid(); is a bug1, and it seems that that bug is now fixed: await nonFutureVoid(); is an error if you use Dart 2.12 or later and enable null-safety and the stricter type-checking that comes with it.

You can observe the old and new behaviors with DartPad by toggling the "Null Safety" button: https://dartpad.dartlang.org/b0dae0d5a50e302d26d93f2db3fa6207


1 There are a lot of issues filed on GitHub with a lot of back-and-forth discussion, so yes, it is rather confusing. Most people seemed to agree that allowing await void was undesirable, however.

Solution 2

A void function indicates that the function returns nothing, which means you can not act on the result of that Function (and cannot await on it's result).

Meanwhile, the Future<void> function returns a Future object (that has value of void). If you don't have a return statement, a missing_return warning will show up (it can still be compiled). You can still act on that result by awaiting it, but cannot actually use the value because it's void.

While it seems like it'd be just fine with whatever you are using, I think it's better to use Future for every async function for type-safety and better maintenance.

Share:
1,195
Nerdy Bunz
Author by

Nerdy Bunz

Hi. Coding and creating new things gets me excited like a fizzy drink, but sometimes I run into headaches, so I come here for help. But I make sure to help other people too, so I think it works out. Apparently my posts often contain language considered extraneous by the pool cleaning robots who dutifully scrub it away on their regular patrols. "Bzzzz! Bzzzz!!! Desaturate, desaturate!" Fortunately, it's ACCESS DENIED for any editing attempts on this lil' article. They'll have to re-route the encryptions... and good luck with that. Oooo! Butterfly!!!! Anyway... when I'm not on here, I like to spend time sniffing and paddling my way around the enchanted river-forest near my house... and knitting my very own apps.

Updated on December 27, 2022

Comments

  • Nerdy Bunz
    Nerdy Bunz over 1 year

    In Dart,

    what is the difference between saying

    Future<void> doStuff() async { ...
    

    and

    void doStuff() async { ...
    

    I know what a Future<T> is and how async/await work generally, but I never realized Future<void> was a thing. I have some code that has the Future<void> all over the place and I want to replace it with my normal way of doing things, but I don't want to break anything.

    Notice that both functions use async. The question is NOT 'what is the difference between async and non-async functions?' or 'can you give a brief attempt at explaining asynchronous programming in Dart, please?'

    I'm aware that there is a pretty much identical question already, but if you look closely at the answers you will see nobody actually answered the question in a clear way -- what is the difference? Is there any difference? Is there no difference?

    To elaborate, consider the following two functions:

    // notice there is no warning about not returning anything
    Future<void> futureVoid() async {
        await Future.delayed(Duration(seconds: 2), () {
          var time = DateTime.now().toString();
          print('$time : delay elapsed');
        });
    }
    
    void nonFutureVoid() async {
        await Future.delayed(Duration(seconds: 2), () {
          var time = DateTime.now().toString();
          print('$time : delay elapsed');
        });
    }
    

    Then test them with a button whose onPressed() function is:

    onPressed: () async {
        await nonFutureVoid(); // notce that this await *DOES* delay execution of the proceeding lines.
        var time = DateTime.now().toString();
        print('$time : <-- executed after await statement');
    }
    

    Log result:

    flutter: 2021-02-23 21:46:07.436496 : delay elapsed
    flutter: 2021-02-23 21:46:07.437278 : <-- executed after await statement
    

    As you can see, they both behave exactly the same way -- the simple void async version IS awaited. So what is the difference? Thanks.