Scala Introduction
&
Futures and Promises

Slides: http://arild.github.io/scala-workshop
Code: https://github.com/arild/scala-workshop

Arild Nilsen
Sjur Millidahl

October, 2013

Outline

  • Introduction
    • Functions
    • Collections
    • Pattern matching
  • Futures and Promises
    • Exercises using Futures
    • Futures vs. Promises

Functional Programming

Functions in Scala

Named functions

def createList(param1: Int, param2: Int): List[Int] = {
    val myImmutableList = List(param1, param2)
    myImmutableList
}

Anonymous functions

(x: Int) => x + 1

Can be accepted as a parameter

def myMethod(n: Int, f: Int => Boolean) = f(n)

Collections in Scala

seq

scala.immutable.List

  • Implements isEmpty, head and tail.
  • O(n) on most operations
  • O(1) on prepend and head/tail-access
  • Suitable for recursive solutions based on head:tail-access
  • Examples:
    scala> 4 :: List(1, 2, 3) // Prepend, O(1)
    res0: List[Int] = List(4, 1, 2, 3)
    scala> List(1, 2, 3) ::: List(4) // Append, O(n), prefer prepend
    res1: List[Int] = List(1, 2, 3, 4)

map()

  • map() takes in a function and applies it to all elements
  • map() transforms the list according to the function provided
scala> val numbers = List(1,2,3)
numbers: List[Int] = List(1, 2, 3)

scala> numbers.map((x: Int) => x + 1)
res0: List[Int] = List(2, 3, 4)

filter()

  • filter() takes inn a function predicate
  • filter() returns the subset of this list for which the predicate is true
scala> val myList = List(1,2,3,4,5,6)
myList: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> myList.filter((x: Int) => x > 3)
res0: List[Int] = List(4, 5, 6)

scala.immutable.List API examples

//Adds an element at the beginning of this list
def ::(x: A): List[A]

//Adds the elements of a given list in front of this list
def :::(prefix: List[A]): List[A]

//Selects the first element of this list
def head: A

//Selects last n elements
def takeRight(n: Int): List[A]

//Selects all elements of this list which satisfy a predicate
def filter(p: (A) ⇒ Boolean): List[A]

Pattern matching

match on any sort of data with a first-match policy.

def toYesOrNo(choice: Int): String = choice match {
    case 1 => "yes"
    case 0 => "no"
    case _ => "error"
}

Pattern matching II

def f(x: Any): String = x match {
    case i:Int => "integer: " + i
    case _:Double => "a double"
    case s:String => "I want to say " + s
}

Do exersices

  • git clone https://github.com/arild/scala-workshop.git
  • Complete predefined tests for MyIntroProblems
  • Complete predefined tests for MyAdvancedProblems

Futures and Promises

  • SIP-14 - redesign of scala.concurrent
  • Introduced in Scala 2.10
  • Placeholder object for a result that does not yet exist

SIP-14 definition

A Future is a read-handle to a single value (read-many) that may be available within a specific time-frame
A Promise is a write-handle to a single value (write-once) that should be made available within a specific time-frame

Hello Future

println("Test print before future")
val s = "hello"

val f = future {
  Thread.sleep(10)
  s + " future!"
}

println("Test print after future")

// Completely asynchronous
f.onSuccess { case s => println(s) }

// Blocks until the future is ready
Await.ready(f, Duration.Inf)
Output:
Test print before future
Test print after future
hello future!

Basic Operations on Futures

//Asynchronously processes the value in 
//the future once the value becomes available.
def foreach[U](f: T => U): Unit

//Creates a new future by applying a function to the successful
//result of this future.
def map[S](f: T => S): Future[S]

//Creates a new future by applying a function to the successful 
//result of this future, and returns the result of the function
//as the new future.
def flatMap[S](f: T => Future[S]): Future[S]

//Creates a new future by filtering the value of the current future
//with a predicate.
def filter(p: T => Boolean): Future[T]

Error handling

val riskyRes = future { riskyWork() }
val safeRes = future { safeWork() }

val finalRes = riskyRes recoverWith {
  case e: IllegalArgumentException => safeRes
}

Futures are composeable

val keys = future { readFile("keys.txt") }
val values = future { readFile("values.txt") }

val data = keys.zip(values)

val hashMap = data.map((ls: (List[String], List[String])) => {
  ls._1.zip(ls._2).toMap
})

hashMap.recover {
  case e: FileNotFoundException => {
    Map[String, String]()
  }
}.onSuccess {
  case map => {
    println(map)
  }
}

Await.result(hashMap, Duration.Inf)

Do exersices

  • git clone https://github.com/arild/scala-workshop.git
  • Complete predefined tests for MyFutures

"Futures" vs. "Promises"

  • "Future", "promise", "delay" and "deferred" used interchangeably
  • Complementary primitives
  • "Promise" exclusively used in the JavaScript world

Producer Consumer Example

val p = promise[T]
val f = p.future

val producer = future {
  val result = produceSomething()
  p success result
  continueDoingSomethingUnrelated()
}

val consumer = future {
  startDoingSomething()
  f onSuccess {
    case res => doSomething(res)
  }
}

Resources

Questions?

Slides: http://arild.github.io/scala-workshop
Code: https://github.com/arild/scala-workshop