Search code examples
nesteddartmailernested-function

DART function, nested / inner functions variable


I've the below code as anonymous function (also function literal or lambda abstraction), which is used in DART mailer

email(){ 
   ...
   emailTransport.send(envelope)
   .then((success) => print('Email sent! $success'))
   .catchError((e) => print('Error occured: $e'));
}

this worked fine, but I need to replace the "print" by a "return" to be like below:

email(){ 
   ...
   emailTransport.send(envelope)
   .then((success) => return 'Email sent! $success')
   .catchError((e) => return 'Error occured: $e');
}

but failed, the return had not been recognized!

I tried the below code, but failed too.

email(){ 
   ...
   var msg;
   ...
   emailTransport.send(envelope)
   .then((success) => msg = 'Email sent! $success')
   .catchError((e) => msg = 'Error occured: $e');

 return msg;
}

But the "msg" remained NULL!

any thoughts.


Solution

  • This is because the return in your function is not part of the chain of Futures that are executing your code. Your function is returning immediately; and the emailTransport.send method has not run yet.

    Your function needs to return a Future; I don't think there is any way to "block" and wait for the result (and if there was, you probably wouldn't want to do this!).

    You probably want to do something like this:

    Future email() {
      ...
      return emailTransport.send(envelope)
       .then((success) => 'Email sent! $success')
       .catchError((e) => 'Error occured: $e');
    }
    

    And then, anything calling the function will need to also chain onto the future:

    email()
      .then(msg => print(msg));
    

    Edit: based on comment

    The original method you're calling is asynchronous, so returns a Future (eg. something that will complete in the future). To do anything with this value, you need to "chain" more code onto the end (which as a result, will also return a Future, because it can't run until the first is completed).

    You can assign to a variable inside a chained function, eg.

    email().then((m) => msg = m);
    

    However, this will only be executed once the async operation has completed, so it will not be immediately available after this line of code (this was ths mistake in your original code sample). If you want to do something with the value, you really need to chain that into the future too:

    email()
      .then(doSomeOtherThing)
    
    doSomeOtherThing(String msg) {
      // Do more processing here
    }
    

    If you're not familiar with Futures, there's an article on the Dart site that might be worth reading: Use Future-Based APIs

    It's very similar to how NodeJS works, nothing should ever "block", but instead, work that needs to be done after async/long-running work is effectively in a callback that gets tagged onto the end, and the runtime sits in a big loop processing what's next on the queue. There's a little more info on this here: The Event Loop and Dart.