So far in my exploration of Dart I have mostly confined myself to familiar territory. Tonight I begin playing with some of the new stuff that the language brings to the table, starting with Futures.
I know that node.js used to have promises, but they were removed very early on in the project as unnecessary. I am curious why Dart elevates a thing to first order construct when it was deemed unneeded in node, but mostly I would simply like to get it working.
I much appreciate the Dart lang documentation suggesting that I get a future from "somewhere" (
getFutureFromSomewhere()
). Fortunately, it does not take too much hunting to find a somewhere in the core language—Completer (benefits of picking up a language when it is still small).The completer needs a type, so I try strings:
main() { var completer = new Completer<String>(); }That compiles, so I know that I am not completely lost. Next up, I grab the future from my completer:
main() { var completer = new Completer<String>(); var future = completer.future; }Again, it compiles, so I think I am OK.
I have my future and completer, that means it is time to do something with both. Successful completion will invoke the
then()
message on the future with whatever message the completer sends. I also need to trigger the completion by calling complete()
on the completer:main() { var completer = new Completer<String>(); var future = completer.future; future.then((message) { print("Future completed with message: " + message); }); completer.complete("foo"); }(try.dartlang.org)
Yay! That works:
➜ command_line git:(master) ✗ dart futures01.dart Future completed with message: fooAh, interesting. The call to
then()
on the future is supplying an anonymous function as a callback to be invoked when the future is done. The anonymous function syntax in Dart makes it read almost like defining the then()
method directly on the future object. I think I am beginning to appreciate Dart's function syntax.Futures promise to be quite useful with the eventful nature of web applications. I will explore that another day. For now, I try a few other things like passing a second
complete()
message to the completer:main() { var completer = new Completer<String>(); var future = completer.future; future.then((message) { print("Future completed with message: " + message); }); completer.complete("foo"); completer.complete("bar"); }(try.dartlang.org)
Locally that results in a "future already completed exception:
➜ command_line git:(master) ✗ dart futures01.dart Future completed with message: foo Unhandled exception: Exception: future already completed 0. Function: 'FutureImpl._setValue@924b4b8' url: 'bootstrap_impl' line:3143 col:7 1. Function: 'CompleterImpl.complete' url: 'bootstrap_impl' line:3173 col:26 2. Function: '::main' url: '/home/cstrom/repos/dart-site/examples/command_line/futures01.dart' line:10 col:21Interestingly, that exception comes from the completer, not the future, but the message indicates that it is a future error.
Speaking of errors, it is also possible to signal the future that an exceptional condition has occurred:
main() { var completer = new Completer<String>(); var future = completer.future; future.then((message) { print("Future completed with message: " + message); }); var exception = new Exception("Too awesome"); completer.completeException(exception); }That results in a runtime error because the future does not know how to handle it:
➜ command_line git:(master) ✗ dart futures02.dart Unhandled exception: Exception: Too awesome 0. Function: 'FutureImpl._complete@924b4b8' url: 'bootstrap_impl' line:3136 col:9 1. Function: 'FutureImpl._setException@924b4b8' url: 'bootstrap_impl' line:3158 col:14 2. Function: 'CompleterImpl.completeException' url: 'bootstrap_impl' line:3177 col:30 3. Function: '::main' url: '/home/cstrom/repos/dart-site/examples/command_line/futures02.dart' line:10 col:30To prevent the runtime error, I need to define a
handleException()
method and signal that all is well by returning true
from that callback:main() { var completer = new Completer<String>(); var future = completer.future; future.then((message) { print("Future completed with message: " + message); }); future.handleException((e) { print("Handled: " + e); return true; }); var exception = new Exception("Too awesome"); completer.completeException(exception); }(try.dartlang.org)
That results in:
➜ command_line git:(master) ✗ dart futures02.dart Handled: Exception: Too awesomeNice! There is certainly some power in these little beasties.
Day #254
I don't know why node maintainers did remove futures. It sounded like an interesting concept.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteNice post, this sure can be an unfamiliar territory for many programmers new to Dart. I liked your simple and straight forward examples.
ReplyDeleteFor people new to Dart trying this stuff out I'd like to point out that Dart's string interpolation syntax has change a bit so you need to change some rows to look like this:
print("Handled: + $e");
instead of this:
print("Handled: " + e);