Changing Doc from Akkas futures to Scalas futures and cleanup of examples. See #2314

This commit is contained in:
Björn Antonsson 2012-08-30 12:18:01 +02:00
parent 042f9f8206
commit 217a9c2cf9
3 changed files with 34 additions and 33 deletions

View file

@ -6,9 +6,10 @@ Futures (Java)
Introduction Introduction
------------ ------------
In Akka, a `Future <http://en.wikipedia.org/wiki/Futures_and_promises>`_ is a data structure used In Scala, a `Future <http://en.wikipedia.org/wiki/Futures_and_promises>`_ is a data structure used
to retrieve the result of some concurrent operation. This operation is usually performed by an ``Actor`` or to retrieve the result of some concurrent operation. This result can be accessed synchronously (blocking)
by the ``Dispatcher`` directly. This result can be accessed synchronously (blocking) or asynchronously (non-blocking). or asynchronously (non-blocking). To be able to use this from Java, Akka provides a java friendly interface
in ``akka.dispatch.Futures``.
Execution Contexts Execution Contexts
------------------ ------------------
@ -27,7 +28,7 @@ Use with Actors
There are generally two ways of getting a reply from an ``UntypedActor``: the first is by a sent message (``actorRef.tell(msg)``), There are generally two ways of getting a reply from an ``UntypedActor``: the first is by a sent message (``actorRef.tell(msg)``),
which only works if the original sender was an ``UntypedActor``) and the second is through a ``Future``. which only works if the original sender was an ``UntypedActor``) and the second is through a ``Future``.
Using the ``ActorRef``\'s ``ask`` method to send a message will return a Future. Using the ``ActorRef``\'s ``ask`` method to send a message will return a ``Future``.
To wait for and retrieve the actual result the simplest method is: To wait for and retrieve the actual result the simplest method is:
.. includecode:: code/docs/future/FutureDocTestBase.java .. includecode:: code/docs/future/FutureDocTestBase.java
@ -68,7 +69,7 @@ Or failures:
Functional Futures Functional Futures
------------------ ------------------
Akka's ``Future`` has several monadic methods that are very similar to the ones used by ``Scala``'s collections. Scala's ``Future`` has several monadic methods that are very similar to the ones used by ``Scala``'s collections.
These allow you to create 'pipelines' or 'streams' that the result will travel through. These allow you to create 'pipelines' or 'streams' that the result will travel through.
Future is a Monad Future is a Monad
@ -81,12 +82,12 @@ The return value of the ``map`` method is another ``Future`` that will contain t
.. includecode:: code/docs/future/FutureDocTestBase.java .. includecode:: code/docs/future/FutureDocTestBase.java
:include: imports2,map :include: imports2,map
In this example we are joining two strings together within a Future. Instead of waiting for f1 to complete, In this example we are joining two strings together within a ``Future``. Instead of waiting for f1 to complete,
we apply our function that calculates the length of the string using the ``map`` method. we apply our function that calculates the length of the string using the ``map`` method.
Now we have a second Future, f2, that will eventually contain an ``Integer``. Now we have a second ``Future``, f2, that will eventually contain an ``Integer``.
When our original ``Future``, f1, completes, it will also apply our function and complete the second Future When our original ``Future``, f1, completes, it will also apply our function and complete the second ``Future``
with its result. When we finally ``get`` the result, it will contain the number 10. with its result. When we finally ``get`` the result, it will contain the number 10.
Our original Future still contains the string "HelloWorld" and is unaffected by the ``map``. Our original ``Future`` still contains the string "HelloWorld" and is unaffected by the ``map``.
Something to note when using these methods: if the ``Future`` is still being processed when one of these methods are called, Something to note when using these methods: if the ``Future`` is still being processed when one of these methods are called,
it will be the completing thread that actually does the work. it will be the completing thread that actually does the work.
@ -115,7 +116,7 @@ to have this done concurrently, and for that we use ``flatMap``:
.. includecode:: code/docs/future/FutureDocTestBase.java .. includecode:: code/docs/future/FutureDocTestBase.java
:include: flat-map :include: flat-map
Now our second Future is executed concurrently as well. This technique can also be used to combine the results Now our second ``Future`` is executed concurrently as well. This technique can also be used to combine the results
of several Futures into a single calculation, which will be better explained in the following sections. of several Futures into a single calculation, which will be better explained in the following sections.
If you need to do conditional propagation, you can use ``filter``: If you need to do conditional propagation, you can use ``filter``:
@ -157,7 +158,7 @@ That's all it takes!
If the sequence passed to ``fold`` is empty, it will return the start-value, in the case above, that will be empty String. If the sequence passed to ``fold`` is empty, it will return the start-value, in the case above, that will be empty String.
In some cases you don't have a start-value and you're able to use the value of the first completing Future In some cases you don't have a start-value and you're able to use the value of the first completing ``Future``
in the sequence as the start-value, you can use ``reduce``, it works like this: in the sequence as the start-value, you can use ``reduce``, it works like this:
.. includecode:: code/docs/future/FutureDocTestBase.java .. includecode:: code/docs/future/FutureDocTestBase.java
@ -172,7 +173,7 @@ Callbacks
--------- ---------
Sometimes you just want to listen to a ``Future`` being completed, and react to that not by creating a new Future, but by side-effecting. Sometimes you just want to listen to a ``Future`` being completed, and react to that not by creating a new Future, but by side-effecting.
For this Akka supports ``onComplete``, ``onSuccess`` and ``onFailure``, of which the latter two are specializations of the first. For this Scala supports ``onComplete``, ``onSuccess`` and ``onFailure``, of which the latter two are specializations of the first.
.. includecode:: code/docs/future/FutureDocTestBase.java .. includecode:: code/docs/future/FutureDocTestBase.java
:include: onSuccess :include: onSuccess
@ -188,8 +189,8 @@ Ordering
Since callbacks are executed in any order and potentially in parallel, Since callbacks are executed in any order and potentially in parallel,
it can be tricky at the times when you need sequential ordering of operations. it can be tricky at the times when you need sequential ordering of operations.
But there's a solution! And it's name is ``andThen``, and it creates a new Future with But there's a solution! And it's name is ``andThen``, and it creates a new ``Future`` with
the specified callback, a Future that will have the same result as the Future it's called on, the specified callback, a ``Future`` that will have the same result as the ``Future`` it's called on,
which allows for ordering like in the following sample: which allows for ordering like in the following sample:
.. includecode:: code/docs/future/FutureDocTestBase.java .. includecode:: code/docs/future/FutureDocTestBase.java

View file

@ -117,7 +117,7 @@ class FutureDocSpec extends AkkaSpec {
val f1 = Future { val f1 = Future {
"Hello" + "World" "Hello" + "World"
} }
val f2 = Promise.successful(3).future val f2 = Future.successful(3)
val f3 = f1 map { x val f3 = f1 map { x
f2 map { y f2 map { y
x.length * y x.length * y
@ -132,7 +132,7 @@ class FutureDocSpec extends AkkaSpec {
val f1 = Future { val f1 = Future {
"Hello" + "World" "Hello" + "World"
} }
val f2 = Promise.successful(3).future val f2 = Future.successful(3)
val f3 = f1 flatMap { x val f3 = f1 flatMap { x
f2 map { y f2 map { y
x.length * y x.length * y
@ -145,7 +145,7 @@ class FutureDocSpec extends AkkaSpec {
"demonstrate usage of filter" in { "demonstrate usage of filter" in {
//#filter //#filter
val future1 = Promise.successful(4).future val future1 = Future.successful(4)
val future2 = future1.filter(_ % 2 == 0) val future2 = future1.filter(_ % 2 == 0)
val result = Await.result(future2, 1 second) val result = Await.result(future2, 1 second)
result must be(4) result must be(4)
@ -290,8 +290,8 @@ class FutureDocSpec extends AkkaSpec {
val msg1 = -1 val msg1 = -1
//#try-recover //#try-recover
val future = akka.pattern.ask(actor, msg1) recoverWith { val future = akka.pattern.ask(actor, msg1) recoverWith {
case e: ArithmeticException Promise.successful(0).future case e: ArithmeticException Future.successful(0)
case foo: IllegalArgumentException Promise.failed[Int](new IllegalStateException("All br0ken!")).future case foo: IllegalArgumentException Future.failed[Int](new IllegalStateException("All br0ken!"))
} }
//#try-recover //#try-recover
Await.result(future, 1 second) must be(0) Await.result(future, 1 second) must be(0)
@ -343,7 +343,7 @@ class FutureDocSpec extends AkkaSpec {
Await.result(future, 1 second) must be("foo") Await.result(future, 1 second) must be("foo")
} }
{ {
val future = Promise.failed[String](new IllegalStateException("OHNOES")).future val future = Future.failed[String](new IllegalStateException("OHNOES"))
//#onFailure //#onFailure
future onFailure { future onFailure {
case ise: IllegalStateException if ise.getMessage == "OHNOES" case ise: IllegalStateException if ise.getMessage == "OHNOES"
@ -367,12 +367,12 @@ class FutureDocSpec extends AkkaSpec {
} }
} }
"demonstrate usage of Promise.success & Promise.failed" in { "demonstrate usage of Future.successful & Future.failed" in {
//#successful //#successful
val future = Promise.successful("Yay!").future val future = Future.successful("Yay!")
//#successful //#successful
//#failed //#failed
val otherFuture = Promise.failed[String](new IllegalArgumentException("Bang!")).future val otherFuture = Future.failed[String](new IllegalArgumentException("Bang!"))
//#failed //#failed
Await.result(future, 1 second) must be("Yay!") Await.result(future, 1 second) must be("Yay!")
intercept[IllegalArgumentException] { Await.result(otherFuture, 1 second) } intercept[IllegalArgumentException] { Await.result(otherFuture, 1 second) }

View file

@ -7,9 +7,9 @@ Futures (Scala)
Introduction Introduction
------------ ------------
In Akka, a `Future <http://en.wikipedia.org/wiki/Futures_and_promises>`_ is a data structure used to In Scala, a `Future <http://en.wikipedia.org/wiki/Futures_and_promises>`_ is a data structure used to
retrieve the result of some concurrent operation. This operation is usually performed by an ``Actor`` retrieve the result of some concurrent operation. This result can be accessed synchronously (blocking)
or by the ``Dispatcher`` directly. This result can be accessed synchronously (blocking) or asynchronously (non-blocking). or asynchronously (non-blocking).
Execution Contexts Execution Contexts
------------------ ------------------
@ -28,7 +28,7 @@ Use With Actors
There are generally two ways of getting a reply from an ``Actor``: the first is by a sent message (``actor ! msg``), There are generally two ways of getting a reply from an ``Actor``: the first is by a sent message (``actor ! msg``),
which only works if the original sender was an ``Actor``) and the second is through a ``Future``. which only works if the original sender was an ``Actor``) and the second is through a ``Future``.
Using an ``Actor``\'s ``?`` method to send a message will return a Future. To wait for and retrieve the actual result the simplest method is: Using an ``Actor``\'s ``?`` method to send a message will return a ``Future``. To wait for and retrieve the actual result the simplest method is:
.. includecode:: code/docs/future/FutureDocSpec.scala .. includecode:: code/docs/future/FutureDocSpec.scala
:include: ask-blocking :include: ask-blocking
@ -61,7 +61,7 @@ with the return value of the block used to complete the ``Future`` (in this case
Unlike a ``Future`` that is returned from an ``Actor``, this ``Future`` is properly typed, Unlike a ``Future`` that is returned from an ``Actor``, this ``Future`` is properly typed,
and we also avoid the overhead of managing an ``Actor``. and we also avoid the overhead of managing an ``Actor``.
You can also create already completed Futures using the ``Promise`` companion, which can be either successes: You can also create already completed Futures using the ``Future`` companion, which can be either successes:
.. includecode:: code/docs/future/FutureDocSpec.scala .. includecode:: code/docs/future/FutureDocSpec.scala
:include: successful :include: successful
@ -74,7 +74,7 @@ Or failures:
Functional Futures Functional Futures
------------------ ------------------
Akka's ``Future`` has several monadic methods that are very similar to the ones used by Scala's collections. Scala's ``Future`` has several monadic methods that are very similar to the ones used by Scala's collections.
These allow you to create 'pipelines' or 'streams' that the result will travel through. These allow you to create 'pipelines' or 'streams' that the result will travel through.
Future is a Monad Future is a Monad
@ -185,20 +185,20 @@ That's all it takes!
If the sequence passed to ``fold`` is empty, it will return the start-value, in the case above, that will be 0. If the sequence passed to ``fold`` is empty, it will return the start-value, in the case above, that will be 0.
In some cases you don't have a start-value and you're able to use the value of the first completing Future in the sequence In some cases you don't have a start-value and you're able to use the value of the first completing ``Future`` in the sequence
as the start-value, you can use ``reduce``, it works like this: as the start-value, you can use ``reduce``, it works like this:
.. includecode:: code/docs/future/FutureDocSpec.scala .. includecode:: code/docs/future/FutureDocSpec.scala
:include: reduce :include: reduce
Same as with ``fold``, the execution will be done asynchronously when the last of the Future is completed, Same as with ``fold``, the execution will be done asynchronously when the last of the ``Future`` is completed,
you can also parallelize it by chunking your futures into sub-sequences and reduce them, and then reduce the reduced results again. you can also parallelize it by chunking your futures into sub-sequences and reduce them, and then reduce the reduced results again.
Callbacks Callbacks
--------- ---------
Sometimes you just want to listen to a ``Future`` being completed, and react to that not by creating a new Future, but by side-effecting. Sometimes you just want to listen to a ``Future`` being completed, and react to that not by creating a new ``Future``, but by side-effecting.
For this Akka supports ``onComplete``, ``onSuccess`` and ``onFailure``, of which the latter two are specializations of the first. For this Scala supports ``onComplete``, ``onSuccess`` and ``onFailure``, of which the latter two are specializations of the first.
.. includecode:: code/docs/future/FutureDocSpec.scala .. includecode:: code/docs/future/FutureDocSpec.scala
:include: onSuccess :include: onSuccess