2. PLANET OS - APRIL 2016
Advanced Scala
• Advanced features are mostly meant for writing new
• Libraries
• Frameworks
• Domain Specific Languages (DSLs)
• Language extensions
• Application developer mostly needs to know these features
• To efficiently use the libraries
• To efficiently debug issues
• To understand weird typing errors
5. PLANET OS - APRIL 2016
Higher Order Functions
class List[A] {
def filter(f : A => Boolean) : List[A]
def map[B](f : A => B) : List[B]
def foldLeft[B](z: B)(f: (B, A) => B): B
def foldRight[B](z: B)(f: (A, B) => B): B
}
• Higher order functions take/return functions as arguments
6. PLANET OS - APRIL 2016
Call-by-Name Parameters
• Call-by-name parameters are not executed at the time of call
def runLater[R](f: => R) = {
new Thread(
new Runnable {
def run { val result = f; … }
}
).start()
}
runLater {
blockingExpensiveFun()
}
7. PLANET OS - APRIL 2016
Implicit Conversions
• Implicit conversions are implemented with implicit methods
object A2BUtils {
implicit def convertA2B(a:A):B = …
}
import A2BUtils._
val a:A = …
val b:B = a // convertA2B(a)
8. PLANET OS - APRIL 2016
Extension Methods
• Extensions methods can be implemented with implicit
classes
implicit class DurationInt(private val n: Int) {
def seconds = {
Duration(n.toLong, TimeUnit.SECONDS)
}
}
5.seconds // new DurationInt(5).seconds
9. PLANET OS - APRIL 2016
Implicit Parameters
• Methods & classes can have implicit parameters
def work(…)(implicit timeout:Duration) = {
…
}
implicit val myDuration = 5.seconds
work(…) // work(…)(myDuration)
10. PLANET OS - APRIL 2016
Type Classes aka Ad-Hoc Polymorphism
• Type classes can be implemented using implicits
trait Ordering[T] {
def compare(x: T, y: T): Int
}
def min[T](a:T, b:T)(implicit o:Ordering[T]) = …
// Define ordering of Ints
implicit object IntOrdering extends Ordering[Int] {
def compare(x: Int, y: Int) = x - y
}
min(5,6) // min(5,6)(IntOrdering)
11. PLANET OS - APRIL 2016
Type Classes aka Ad-Hoc Polymorphism
• Type classes can be implemented using implicits
trait Ordering[T] {
def compare(x: T, y: T): Int
}
// These two are equivalent
def min[T](a:T, b:T)(implicit o:Ordering[T]) = …
def min[T:Ordering](a:T, b:T) =
if (implicitly[Ordering[T]].compare(a,b))
a
else
b
}
12. PLANET OS - APRIL 2016
Futures
• Is a way to asynchronously retrieve the result of a concurrent
operation
def blockingExpensiveFun() : Result = { … }
val resultFuture : Future[Result] =
Future {
blockingExpensiveFun() : Result
}
13. PLANET OS - APRIL 2016
Execution Context
• Is an abstraction for running Runnable
• It is usually passed around implicitly
implicit val executionContext: ExecutionContext = …
val resultFuture: Future[Result] =
Future {
blockingExpensiveFun()
}//(executionContext)
14. PLANET OS - APRIL 2016
Awaiting Future Results
• Synchronously await future result with timeout
import scala.concurrent._
import scala.concurrent.duration._
val resultFuture =
Future {
blockingExpensiveFun()
}
// In most cases You shouldn’t do that :)
val result = Await.result(resutFuture, 15.seconds)
15. PLANET OS - APRIL 2016
Future Results & Callbacks
• Futures can succeed or fail
val resultFuture: Future[Result] = Future {
blockingExpensiveFun()
}
resultFuture onComplete {
case Success(result) => …
case Failure(throwable) => …
}
16. PLANET OS - APRIL 2016
Promises
• Promises are used to communicate values between threads
trait Promise[R] {
def future : Future[R]
def success(result:R)
}
17. PLANET OS - APRIL 2016
Promises
• Promises are used to communicate values between threads
def runLater[R](f: => R) : Future[R] = {
val promise = Promise[R]()
new Thread(new Runnable {
def run {
val result = f; promise.success(result)
}}).start()
promise.future
}
val resultFuture:Future[R] = runLater{
blockingExpensiveFun()
}
18. PLANET OS - APRIL 2016
Futures Can be Composed: … using Callback Hell
val rateQuote = Future {
connection.getCurrentValue(USD)
}
rateQuote onSuccess { case quote =>
val purchase = Future {
if (isProfitable(quote)) connection.buy(amount, quote)
else throw new Exception("not profitable")
}
purchase onSuccess {
case _ => println("Purchased " + amount + " USD")
}
}
19. PLANET OS - APRIL 2016
Futures Can be Composed: … or using Monad nirvana
val usdQuote = Future { connection.getCurrentValue(USD) }
val chfQuote = Future { connection.getCurrentValue(CHF) }
val purchase = for {
usd <- usdQuote
chf <- chfQuote
if isProfitable(usd, chf)
} yield connection.buy(amount, chf)
purchase onSuccess {
case _ => println("Purchased " + amount + " CHF")
}
20. PLANET OS - APRIL 2016
For-Comprehensions are Syntactic Sugar for Monads
val purchase = usdQuote.flatMap {
usd =>
chfQuote
.withFilter(chf => isProfitable(usd, chf))
.map(chf => connection.buy(amount, chf))
}
val purchase = for {
usd <- usdQuote
chf <- chfQuote
if isProfitable(usd, chf)
} yield connection.buy(amount, chf)
21. PLANET OS - APRIL 2016
For Comprehensions
• For comprehensions work with any Monad
• Examples of monads:
• Seq
• List
• Option
• Either
• Try
• …
22. PLANET OS - APRIL 2016
For Comprehensions: Seq Example
val list : Seq[(Int,Int)] =
for(
i <- 0 to 100
j <- i to 2*i
if (i*j % 7 == 0)
) yield (i,j)
23. PLANET OS - APRIL 2016
For Comprehensions: Option Example
sealed trait Option[+T]
case class Some[+T](v:T) extends Option[T]
case object None extends Option[Nothing]
val option : Option[Result] =
for(
i <- mayBeIntermediate() : Option[Intermediate]
r <- mayBeResult(r) : Option[Result]
if check(i, r)
) yield r
24. PLANET OS - APRIL 2016
For-Comprehensions: Desugaring
genA().map(a => f(a))
for{
a <- genA()
} yield f(a)
25. PLANET OS - APRIL 2016
For-Comprehensions: Desugaring
genA().flatMap{ a => genB(a).map(b => f(a,b)) }
for{
a <- genA()
b <- gebB(a)
} yield fun(a,b)
26. PLANET OS - APRIL 2016
For-Comprehensions: Desugaring
genA().flatMap{ a =>
genB(a)
.withFilter{ b => check(a,b) }
.map(b => f(a,b))
)
}
}
for{
a <- genA()
b <- gebB(a)
if check(a,b)
} yield f(a,b)
27. PLANET OS - APRIL 2016
For Comprehensions & Monads
• For comprehensions work with any Monad
• Examples of monads:
• Seq, List, Option, Either, Try
• Futures
• IO, (Side-)Effects
• Query DSLs (Slick)
• Testing DSLs (ScalaCheck)
28. PLANET OS - APRIL 2016
Slick - Functional Relational Mapping (FRM)
select c.name, c.price, s.name
from coffees c join suppliers s
on (c.supID == s.id)
where c.name = "Expresso"
for {
(c, s) <- coffees join suppliers
on (_.supID === _.id)
if c.name === "Espresso"
} yield (c.name, c.price, s.name)
29. PLANET OS - APRIL 2016
ScalaCheck - Random Testing of Program Properties
val ints = Gen.choose(-100, 100)
def leafs: Gen[Leaf] = for {
x <- ints
} yield Leaf(x)
def nodes: Gen[Node] = for {
left <- trees
right <- trees
} yield Node(left, right)
def trees: Gen[Tree] = Gen.oneOf(leafs, nodes)
30. PLANET OS - APRIL 2016
Monads, Monads, Monads, Monads!
31. PLANET OS - APRIL 2016
Monads
All told, a monad in X is just a monoid in the category of
endofunctors of X, with product × replaced by composition of
endofunctors and unit set by the identity endofunctor.
Saunders Mac Lane
Categories for the Working Mathematician
32. PLANET OS - APRIL 2016
Monads in Scala
• Monad is a trait parametrized by higher kinded type, eg
• List[ _ ]
• Option[ _ ]
• …
trait Monad[M[_]] {
def unit[A](a: A): M[A]
def flatMap[A, B](m: M[A])(f: A => M[B]): M[B]
}
33. PLANET OS - APRIL 2016
Monads Laws
• Left identity:
unit(a) >>= f ≡ f(a)
• Right identity:
m >>= (x => unit(x)) ≡ m
• Associativity:
(m >>= f) >>= g ≡ m >>= (x => (f(x) >>= g))
• Operator >>= denotes flatMap
34. PLANET OS - APRIL 2016
List Monad Example
implicit object MonadicList extends Monad[List] {
def unit[A](a:A) : List[A] = List(a)
def flatMap[A,B](l: List[A])
(f: A => List[B]) : List[B] = {
val i:List[List[B]] = l.map(f)
i.flatten
}
}
35. PLANET OS - APRIL 2016
Option Monad Example
implicit object MonadicOption extends Monad[Option] {
def unit[A](a:A) : Option[A] = Some(a)
def flatMap[A,B](opt : Option[A])
(f: A => Option[B]) : Option[B] = {
opt match {
case Some(a) =>
f(a) : Option[B]
case None =>
None
}
}
}
36. PLANET OS - APRIL 2016
Advanced Scala Concepts
• Implicits
• Implicit parameters
• Implicit conversions
• Extension methods
• Type-classes aka Adhoc Polymorphism
• For-comprehensions and Monads
37. PLANET OS - APRIL 2016
Very Advanced Scala Concepts
• Algebra based programming
• Monoids, groups, rings
• Category theory based programming
• Functors, applicative functors, monads, arrows
• Generic programming
• Type-level programming
• Meta-programming
• Scala Reflect
• Scala Meta
38. PLANET OS - APRIL 2016
Scala Libraries / DSLs
• Async - simpler way to write async code
• Parser Combinators - grammar parsing DSL
• ScalaCheck - random testing of program properties
• Algebird - abstract algebra for scala
• Scalaz/Cats - category theory based programming
• Shapeless - generic programming
• Spire - generic numeric computations
39. PLANET OS - APRIL 2016
Projects in Scala
• Slick - functional relational mapping for Scala
• Akka - actor-based reactive programming tookit
• Finagle - fault tolerant, protocol-agnostic RPC system
• Spray - high-performance REST/HTTP for Akka
• Play - high velocity web framework for Java and Scala
• Scalding - Scala library to specify MapReduce jobs
• Spark - in-memory cluster computing
• Kafka - publish-subscribe messaging
• Samza - distributed stream processing framework
40. PLANET OS - APRIL 2016
Scala Advantages
• FP gateway drug for Java developers
• You can treat Scala as Java with prettier syntax
• Runs on JVM, integrates with libraries
• Higher productivity, less lines of code (with type-inference)
• Very suitable for:
• Data processing
• Concurrent/distributed programming
• Libraries/DSLs
• Many errors are caught at compile time (by the type system)
42. PLANET OS - APRIL 2016
Scala Downsides: “Modern C++”
• Shoehorning Scala type system into JVM
• Slowish compile-time forces to modularize
• Brittle across Scala and library versions
• Sometimes scary compiler messages
• Compulsion to use all possible Scala features
• Doesn't prevent from creating write-only code
• Libraries/DSLs can have cryptic operators and types
• Optimized inner loops cannot use any advanced features
• Tooling got much better lately
43. PLANET OS - APRIL 2016
Scala Downsides: Cultural
• Too many different programming styles possible
• Object-oriented
• Basic functional programming
• Advanced functional programming
• Category theory with unicode symbols
• Generic programming
• Type-level programming
• Need to enforce cultural/coding standards in organization
44. PLANET OS - APRIL 2016
Obligatory Moralistic Slide