futures - epfllampphaller/doc/futures-try-sep2012.pdf · java futures neither 2 efficient nor...

76
futures & promises in Scala 2.10 PHILIPP HALLER HEATHER MILLER

Upload: duongtu

Post on 03-Jul-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

futures&promisesin Scala 2.10

PHILIPP HALLERHEATHER MILLER

Page 2: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futures/PromisesAgenda

Execution CtxstRY

Page 3: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

common theme:

Page 4: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

common theme:Pipelining

Page 5: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

future&promise

scala.concurrent.

Page 6: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

First, some Motivation

Page 7: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

1Several important libraries have their own future/promise implementation

Page 8: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

1Several important libraries have their own future/promise implementation

java.util.concurrent.scala.actors.

com.twitter.util.

akka.dispatch.scalaz.concurrent.net.liftweb.actor.

FUTUREFUTUREFUTURE

FUTUREPROMISELAFUTURE

Page 9: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

This makes it clear that...

Page 10: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

This makes it clear that...

futures are an important, powerful abstraction

Page 11: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

This makes it clear that...

futures are an important, powerful abstraction

there’s fragmentation in

the scala ecosystem

no hope of interop!

Page 12: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Furthermore...

Page 13: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Furthermore...Java futures neither efficient nor composable2

Page 14: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Furthermore...Java futures neither efficient nor composable2we could make futures more powerful, by taking advantage of scala’s features

3

Page 15: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

can be thought of as a single concurrency abstraction

Futures&Promises

Future promise

Page 16: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

can be thought of as a single concurrency abstraction

Futures&Promises

Future

READ-MANY

promise

write-once

Page 17: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

can be thought of as a single concurrency abstraction

Futures&Promises

Future

READ-MANY

promise

write-once

Start async computation ✔important ops

Assign result value✔ Wait for result ✔ Obtain associated future object

Page 18: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

a promise p of type Promise[T] can be completed in two ways...

Success&Failure

val result: T = ...p.success(result)

Success

val exc = new Exception(“something went wrong”)p.failure(exc)

Failure

Page 19: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

FuturePromiseFuture with value

GreenRed thread waiting on the

result of another thread

meaningful work

java.util.concurrent.future

Page 20: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

java.util.concurrent.future

FuturePromiseFuture with value

GreenRed thread waiting on the

result of another thread

meaningful work

Page 21: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

what we’d like to do instead

FuturePromiseFuture with value

GreenRed thread waiting on the

result of another thread

meaningful work

Page 22: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Async&NonBlocking

Page 23: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Async&NonBlockinggoal: Do not block current thread while waiting

for result of future

Page 24: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Async&NonBlockinggoal: Do not block current thread while waiting

for result of future

CallbacksRegister callback which is invoked (asynchronously) when future is completed

Async computations never block(except for managed blocking)

Page 25: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Async&NonBlockinggoal: Do not block current thread while waiting

for result of future

CallbacksRegister callback which is invoked (asynchronously) when future is completed

Async computations never block(except for managed blocking)

user doesn’t have to explicitly manage

callbacks. higher-order functions instead!

Page 26: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futures&PromisesThread1 Thread2 Thread3

example

Page 27: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futures&Promises

Promise

val p = Promise[Int]() // Thread 1

Thread1 Thread2 Thread3

(create promise)

example

Page 28: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futures&Promises

PromiseFuture

val p = Promise[Int]() // Thread 1val f = p.future // Thread 1

Thread1 Thread2 Thread3

(create promise)(get reference to future)

example

Page 29: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futures&Promises

PromiseFuture

val p = Promise[Int]() // Thread 1val f = p.future // Thread 1

f onSuccess { // Thread 2 case x: Int => println(“Successful!”)}

Thread1 Thread2 Thread3

onSuccess callback

(create promise)(get reference to future)(register callback)

example

Page 30: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futures&Promises

PromiseFuture

val p = Promise[Int]() // Thread 1val f = p.future // Thread 1

f onSuccess { // Thread 2 case x: Int => println(“Successful!”)}

Thread1 Thread2 Thread3

onSuccess callback

p.success(42) // Thread 1

4242

(create promise)(get reference to future)(register callback)

(write to promise)

example

Page 31: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futures&Promises

PromiseFuture

val p = Promise[Int]() // Thread 1val f = p.future // Thread 1

f onSuccess { // Thread 2 case x: Int => println(“Successful!”)}

Thread1 Thread2 Thread3

onSuccess callback

p.success(42) // Thread 1

4242 Successful!

Console

(create promise)(get reference to future)(register callback)

(write to promise)

(execute callback)// Thread

example

note: onSuccess callback executed even if f has

already been completed at time of registration

Page 32: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Combinators

val purchase: Future[Int] = rateQuote map { quote => connection.buy(amount, quote) }

val postBySmith: Future[Post] = post.filter(_.author == “Smith”)

Composability thru higher-order funcsstandard monadic combinators

def map[S](f: T => S): Future[S]

def filter(pred: T => Boolean): Future[T]

Page 33: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Combinators

val purchase: Future[Int] = rateQuote map { quote => connection.buy(amount, quote) }

val postBySmith: Future[Post] = post.filter(_.author == “Smith”)

Composability thru higher-order funcsstandard monadic combinators

def map[S](f: T => S): Future[S]

def filter(pred: T => Boolean): Future[T]

If filter fails: postBySmith completed with NoSuchElementException

If map fails: purchase is completed with unhandled exception

Page 34: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

CombinatorsAdditional future-specific higher-order functions have been introduced

def fallbackTo[U >: T](that: Future[U]): Future[U]

val fut: Future[T] = Future.firstCompletedOf[T](futures)

def andThen(pf: PartialFunction[...]): Future[T]

Page 35: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

CombinatorsAdditional future-specific higher-order functions have been introduced

def fallbackTo[U >: T](that: Future[U]): Future[U]

val fut: Future[T] = Future.firstCompletedOf[T](futures)

def andThen(pf: PartialFunction[...]): Future[T]

”falls back” to that future in case of failure

returns a future completed with result of first completed future

allows one to define a sequential execution over a chain of futures

Page 36: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

contextExecution

scala.concurrent.

Page 37: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

are needed by:Threadpools...

futures

Actors

parallel collections

for executing callbacks and function arguments

for executing message handlers, scheduled tasks, etc.

for executing data-parallel operations

Page 38: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

contextsExecution

Scala 2.10 introduces

Page 39: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

contextsExecution

Scala 2.10 introduces

provide global threadpool as platform service to be shared by all parallel frameworks

Goal

Page 40: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

contextsExecution

Scala 2.10 introduces

provide global threadpool as platform service to be shared by all parallel frameworks

Goal

scala.concurrent package provides global ExecutionContext

Default ExecutionContext backed by the most recent fork join pool (collaboration with Doug Lea, SUNY Oswego)

Page 41: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Implicit Execution Ctxsdef map[S](f: T => S)(implicit executor: ExecutionContext): Future[S]

def onSuccess[U](pf: PartialFunction[T, U]) (implicit executor: ExecutionContext): Unit

Asynchronous computations are executed on an ExecutionContext which is provided implicitly.

Implicit parameters enable fine-grained selection of the ExecutionContext:

implicit val context: ExecutionContext = customExecutionContextval fut2 = fut1.filter(pred) .map(fun)

Page 42: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Implicit Execution Ctxsdef map[S](f: T => S)(implicit executor: ExecutionContext): Future[S]

def onSuccess[U](pf: PartialFunction[T, U]) (implicit executor: ExecutionContext): Unit

Asynchronous computations are executed on an ExecutionContext which is provided implicitly.

Implicit parameters enable fine-grained selection of the ExecutionContext:

implicit val context: ExecutionContext = customExecutionContextval fut2 = fut1.filter(pred) .map(fun)

implicit ExecutionContexts allow sharing ecs

between frameworks

Enables flexible selection of execution policy

Page 43: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futurethe implementation

def map[S](f: T => S): Future[S] = { val p = Promise[S]()

onComplete { case result => try { result match { case Success(r) => p success f(r) case Failure(t) => p failure t } } catch { case t: Throwable => p failure t } } p.future}

Many operations implemented in terms of promisessimplified example

Page 44: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Futurethe implementationREAL

def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { val p = Promise[S]()

onComplete { case result => try { result match { case Success(r) => p success f(r) case f: Failure[_] => p complete f.asInstanceOf[Failure[S]] } } catch { case NonFatal(t) => p failure t } } p.future}

The real implementation (a) adds an implicit ExecutionContext, (b) avoids extra object creations, and (c) catches only non-fatal exceptions:

Page 45: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Promisethe implementation

Promise is the work horse of the futures implementation.

def complete(result: Try[T]): this.type = if (tryComplete(result)) this else throw new IllegalStateException("Promise already completed.")

A Promise[T] can be in one of two states:

COMPLETED

PENDINGNo result has been written to the promise.State represented using a list of callbacks (initially empty).

The promise has been assigned a successful result or exception.State represented using an instance of Try[T]

Invoking Promise.complete triggers a transition from state Pending to Completed

A Promise can be completed at most once:

Page 46: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

def tryComplete(value: Try[T]): Boolean = { val resolved = resolveTry(value) (try { @tailrec def tryComplete(v: Try[T]): List[CallbackRunnable[T]] = { getState match { case raw: List[_] => val cur = raw.asInstanceOf[List[CallbackRunnable[T]]] if (updateState(cur, v)) cur else tryComplete(v) case _ => null } } tryComplete(resolved) } finally { synchronized { notifyAll() } // Notify any blockers }) match { case null => false case rs if rs.isEmpty => true case rs => rs.foreach(_.executeWithValue(resolved)); true }}

Completing a Promise

Page 47: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

the awkWard squadabstract class AbstractPromise { private volatile Object _ref; final static long _refoffset; static { try { _refoffset = Unsafe.instance.objectFieldOffset( AbstractPromise.class.getDeclaredField("_ref")); } catch (Throwable t) { throw new ExceptionInInitializerError(t); } } protected boolean updateState(Object oldState, Object newState) { return Unsafe.instance.compareAndSwapObject(this, _refoffset, oldState, newState); } protected final Object getState() { return _ref; }}

Page 48: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

IntegratingFutures Actors&Futures are results of asynchronous message sends when a response is expected

Future of Friends is either completed with a successful result or with a wrapped exception if response times out or is not of type Seq[Friend]

val response: Future[Any] = socialGraph ? getFriends(user)

Implementing synchronous send (untyped):

def syncSend(to: ActorRef, msg: Any, timeout: Duration): Any = { val fut = to ? msg Await.result(fut, timeout)}

Recovering typesval friendsFut: Future[Seq[Friend]] = response.mapTo[Seq[Friend]]

Page 49: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

IntegratingFutures Actors&Futures are results of asynchronous message sends when a response is expected

Future of Friends is either completed with a successful result or with a wrapped exception if response times out or is not of type Seq[Friend]

val response: Future[Any] = socialGraph ? getFriends(user)

Implementing synchronous send (untyped):

def syncSend(to: ActorRef, msg: Any, timeout: Duration): Any = { val fut = to ? msg Await.result(fut, timeout)}

Recovering typesval friendsFut: Future[Seq[Friend]] = response.mapTo[Seq[Friend]]

friendsFut is either completed with a successful result or with a wrapped exception if response times out or is not of type Seq[Friend]

Page 50: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TRYscala.util.

Page 51: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

And now onto something completely different.

Page 52: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

And now onto something completely different.

not concurrent,

not asynchronous

Page 53: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Tryis a simple data container

Composable✔Combinators for exceptions✔

Great for monadic-style exception handling.

Divorcing exception handling from the stack.

Page 54: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Tryis a simple data container

sealed abstract class Try[+T]

final case class Success[+T](value: T) extends Try[T]

final case class Failure[+T](exception: Throwable) extends Try[T]

Page 55: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Tryis a simple data container

sealed abstract class Try[+T]

final case class Success[+T](value: T) extends Try[T]

final case class Failure[+T](exception: Throwable) extends Try[T]

Page 56: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Tryis a simple data container

sealed abstract class Try[+T]

final case class Success[+T](value: T) extends Try[T]

final case class Failure[+T](exception: Throwable) extends Try[T]

Page 57: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods onBasic Ops

def get: T

get

Success

Failure

Returns value stored within Success

Throws exception stored within Failure

Page 58: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods on

def getOrElse[U >: T](default: => U): U

Success

Failure

Returns value stored within Success

Returns the given default argument if this is a Failure

getOrElseBasic Ops

Page 59: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods on

def orElse[U >: T](default: => Try[U]): Try[U]

orElse

Success

Failure

Returns this Try if this is a Success

Returns the given default argument if this is a Failure

Basic Ops

Page 60: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods on

def map[U](f: T => U): Try[U]

map

Success

Failure

Applies the function f to the value from Success

Returns this if this is a Failure

monadic Ops

Page 61: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods on

def flatMap[U](f: T => Try[U]): Try[U]

flatMap

Success

Failure

Applies the function f to the value from Success

Returns this if this is a Failure

monadic Ops

Page 62: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods on

def filter(p: T => Boolean): Try[T]

filter

Success

Failure

Converts this to a Failure if predicate p not satisfied.

Returns this if this is a Failure

monadic Ops

Page 63: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods on

def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U]

recoverWith

Success

Failure

Returns this if this is a Success

Applies function f if this is a Failure. (flatMap on exptn)

exception-specific Ops

Page 64: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods on

def recover[U >: T](f: PartialFunction[Throwable, U]): Try[U]

recover

Success

Failure

exception-specific Ops

Returns this if this is a Success

Applies function f if this is a Failure. (map on exptn)

Page 65: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Trymethods on

def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U]

transform

Success

Failure

Creates Try by applying function s if this is a Success

Creates Try by applying function f if this is a Failure

exception-specific Ops

Page 66: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TO BUILDUSING THESE Pipelines

Page 67: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TO BUILDUSING THESE Pipelines

Remember: not concurrent,

not asynchronous

Page 68: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TrySimple pipelining onExample 1

case class Account(acctNum: Int, balance: Double, interestRate: Double)

val withdrawal = 1500val adjustment = 0.4val in = Try(getAcct)

val withdrawalResult = in map { (x: Account) => Account(x.acctNum, x.balance - withdrawal, x.interestRate) } filter { (x: Account) => x.balance > 12000 // acct in good standing } flatMap { (x: Account) => Account(x.acctNum, x.balance, x.interestRate + adjustment) Try(updateAcct) }

Page 69: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TrySimple pipelining onExample 1

case class Account(acctNum: Int, balance: Double, interestRate: Double)

val withdrawal = 1500val adjustment = 0.4val in = Try(getAcct)

val withdrawalResult = in map { (x: Account) => Account(x.acctNum, x.balance - withdrawal, x.interestRate) } filter { (x: Account) => x.balance > 12000 // acct in good standing } flatMap { (x: Account) => Account(x.acctNum, x.balance, x.interestRate + adjustment) Try(updateAcct) }

GETACCT MIGHT FAIL

Page 70: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TrySimple pipelining onExample 1

case class Account(acctNum: Int, balance: Double, interestRate: Double)

val withdrawal = 1500val adjustment = 0.4val in = Try(getAcct)

val withdrawalResult = in map { (x: Account) => Account(x.acctNum, x.balance - withdrawal, x.interestRate) } filter { (x: Account) => x.balance > 12000 // acct in good standing } flatMap { (x: Account) => Account(x.acctNum, x.balance, x.interestRate + adjustment) Try(updateAcct) }

Predicate might not be satisfied

Page 71: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TrySimple pipelining onExample 1

case class Account(acctNum: Int, balance: Double, interestRate: Double)

val withdrawal = 1500val adjustment = 0.4val in = Try(getAcct)

val withdrawalResult = in map { (x: Account) => Account(x.acctNum, x.balance - withdrawal, x.interestRate) } filter { (x: Account) => x.balance > 12000 // acct in good standing } flatMap { (x: Account) => Account(x.acctNum, x.balance, x.interestRate + adjustment) Try(updateAcct) }

UPDATEACCT MIGHT FAIL

Page 72: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TrySimple pipelining onExample 1

case class Account(acctNum: Int, balance: Double, interestRate: Double)

val withdrawal = 1500val adjustment = 0.4val in = Try(getAcct)

val withdrawalResult = in map { (x: Account) => Account(x.acctNum, x.balance - withdrawal, x.interestRate) } filter { (x: Account) => x.balance > 12000 // acct in good standing } flatMap { (x: Account) => Account(x.acctNum, x.balance, x.interestRate + adjustment) Try(updateAcct) }

Eliminates nested try blocksbut how can we handle these failures?

Page 73: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

TrySimple pipelining onExample 2

...by using recoverWith, recover, or orElse case class Tweet(from: String, retweets: Int)

val importantTweets = Try { server.getTweetList } orElse { cachedTweetList } map { twts => val avgRetweet = twts.map(_.retweets).reduce(_ + _) / twts.length (twts, avgRetweet) } filter { case (twts, avgRetweet) => twts.map(_.retweets).exists(_ > avgRetweet) } map { case (twts, avgRetweet) => twts.filter(_.retweets > avgRetweet) } recover { case nose: NoSuchElementException => // handle individually case usop: UnsupportedOperationException => // handle individually case other => // handle individually }

Page 74: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Try&Futurescombining

case class Friend(name: String, age: String) val avgAge = Promise[Int]() val fut = future { // query a social network... List(Friend("Zoe", "25"), Friend("Jean", "27"), Friend("Paul", "3O")) } fut onComplete { tr => // compute average age of friends val result = tr map { friends => friends.map(_.age.toInt).reduce(_ + _) / friends.length } avgAge complete result } avgAge.future onComplete println

Page 75: futures - EPFLlampphaller/doc/Futures-Try-Sep2012.pdf · Java futures neither 2 efficient nor composable ... { // Thread 2 case x: Int => println ... => x.balance > 12000 // acct

Credits

PHILIPP HALLER

ALEX PROKOPEC

VOJIN JOVANOVIC

VIKTOR KLANG MARIUS ERIKSEN

HEATHER MILLER

ROLAND KUHN

DOUG LEA

TYPESAFE

TYPESAFE

EPFL

EPFL

EPFL

TYPESAFE

SUNY

TWITTER

HAVOC PENNINGTONTYPESAFE