aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Haller <hallerp@gmail.com>2013-06-30 12:11:16 -0700
committerPhilipp Haller <hallerp@gmail.com>2013-06-30 12:11:16 -0700
commitf41769c00a47917d82c0c73ef8eba4c71f919092 (patch)
treecd373faa57e2c5cc05c0c6ab20fdd48b8d64fada
parent9156cbeb944db80245766c317f43434b4c1981e5 (diff)
downloadscala-async-f41769c00a47917d82c0c73ef8eba4c71f919092.tar.gz
scala-async-f41769c00a47917d82c0c73ef8eba4c71f919092.tar.bz2
scala-async-f41769c00a47917d82c0c73ef8eba4c71f919092.zip
Add Async tutorial
-rw-r--r--doc/tutorial.md135
1 files changed, 135 insertions, 0 deletions
diff --git a/doc/tutorial.md b/doc/tutorial.md
new file mode 100644
index 0000000..b1cb5a8
--- /dev/null
+++ b/doc/tutorial.md
@@ -0,0 +1,135 @@
+# Async Tutorial
+
+By Philipp Haller
+
+## Preliminaries
+
+Async is a macro library for Scala 2.10.1 or higher. (Since it's
+slated for inclusion in the Scala 2.11 distribution there will be
+binary artifacts for all upcoming Scala 2.11 releases.) To start using
+Async, it suffices to include a compatible binary jar on the
+classpath.
+
+To use Async with the default binding for Scala's futures, the members
+`async` and `await` of the `scala.async.Async` object have to be
+imported. (In a future stable release, these members might be moved
+to the `scala.async` package object.) A language import to enable
+macros is not required for users of async/await.
+
+## The async construct
+
+The `async` construct has the following signature:
+
+ def async[T](body: => T): Future[T]
+
+As can be seen from its type, it creates a future; `body` is a by-name
+parameter which means that it is evaluated asynchronously as the body
+of the future. Calling `async` requires having an implicit
+`ExecutionContext` in scope on which the new future is scheduled for
+execution. If there is no such `ExecutionContext` in scope,
+compilation fails. (Similar to how `future { ... }` works.)
+
+The body of `async` may contain calls to `await` which is explained next.
+
+## The `await` construct
+
+Calling `await` inside the body of an `async` block suspends the
+evaluation of the `async` block until a given future is completed
+(successfully or unsuccessfully). Its signature is as follows:
+
+ def await[T](fut: Future[T]): T
+
+Even though the signature and semantics of `await` are very similar to
+typical blocking calls, calls to `await` are translated to efficient
+non-blocking code under the hood. Example:
+
+ 01: val fut: Future[String] = ...
+ 02:
+ 03: val messageFut = async {
+ 04: // potentially expensive computation
+ 05: val user = ...
+ 06: // to continue we need the result of `fut`:
+ 07: val res = await(fut)
+ 08: val (month, day) = res
+ 09: s"Hello $user, it's $month!"
+ 10: }
+
+In the above example, the evaluation of the body of `async` suspends
+at line 7 until the future `fut` is completed. There are several
+possible outcomes: either `fut` is completed successfully in which case
+the evaluation resumes on line 8 such that `res` is bound to the
+successful result. Another possibility is that `fut` is completed
+with an exception. In that case, `messageFut` is immediately completed
+with the same exception. (A timeout is handled like an unsuccessful
+completion with a `TimeoutException`.)
+
+## Illegal Uses of `await`
+
+The `await` construct can be used within most of Scala's standard
+control structures such as if-else and match expressions. However,
+certain uses of `await` are illegal, since they make it impossible to
+generate the state machine of the `async` block. This section explains
+where it is illegal to use `await` and what options exist to work
+around issues that arise from those restrictions.
+
+The most important limitation of `await` is that it cannot be called
+from within closures inside an `async` block. This means an `await`
+can only occur within a directly enclosing `async` block. Sometimes
+this can be hard to avoid, for example, when calling higher-order
+functions on collections. Here is an example:
+
+ async {
+ val list = ...
+
+ list map { idx =>
+ // need to suspend
+ val res = await(someFut(idx))
+
+ transform(res)
+ }
+ }
+
+The above example will fail to compile since `await` is called inside
+the closure passed to `map`. In situations like this it can be useful
+to wrap (parts of) the closure's body in a nested `async` block. Of
+course, this changes the result type of the `map` call: we're now
+dealing with a collection of futures instead of a collection of strict
+results. Fortunately, the futures API provides a few utilities for
+working with collections of futures. In this case, the `sequence`
+combinator, which converts a collection with elements of type `Future[T]` into a future of a
+collection of elements of type `T`, is most useful:
+
+ async {
+ val list = ...
+
+ val colFuts = list map { idx =>
+ async {
+ // need to suspend
+ val res = await(someFut(idx))
+
+ transform(res)
+ }
+ }
+
+ await(Future.sequence(colFuts))
+ }
+
+Besides closures, there are other points in a program where `await` cannot be used. For example, if the `async` block contains a nested class, trait, or object, it is illegal to call `await` inside of it without an `async` block that directly encloses the `await` call.
+
+Similar to closures, it is illegal to use `await` within an argument of a by-name parameter. In some cases a work-around is to implement the method with the by-name parameter as a macro, so that the method body is inlined. In many cases that's enough to avoid any further issues. However, it is only recommended for advanced users, since the solution relies on using macros.
+
+## Debugging
+
+The Async distribution contains utilities that simplify debugging
+`async` blocks. By importing the `async` and `await` members from the
+`scala.async.BlockingAsync` object instead of from the
+`scala.async.Async` object, a different evaluation strategy for
+`async` blocks is selected. The "blocking" strategy ensures that each
+`async` block is executed on a single thread in such a way that
+execution never leaves that thread. As a result, regular debuggers can
+be used to step through the code of an `async` block without losing
+the thread's stack. To make this possible, in this mode all calls to
+`await` are blocking: the current thread is blocked until the
+corresponding future is completed in which case the thread is
+unblocked to resume its computation.
+