2. day 1: hour 1: Object Orientation Classes, Objects and Traits Generic Types Case Classes, Patter Matching and Tuples hour 2: Functional Programming First-class and Anonymous Functions Higer-Order Functions and Curry Implicit Parameters and Conversions Using Scala features to create a simple DSLday 2: hour 1: Using OO and FP together Structural Typing Scala Collections For-Comprehensions Options and Monads hour 2: Concurrency Abstractions for Concurrency Actors and Remote Actors
3. Do we need a new language? Keep It Simple Vs. Do More With Less
5. The first Scala class class Rational(n: Int, d: Int) { valnum = n val den = d defthis(n: Int) = this(n, 1) def + (that: Rational): Rational = new Rational(num * that.den + that.num * den, den * that.den) def + (i: Int): Rational = new Rational(num + i * den, den) overridedeftoString = "" + num + "/" + den }
6. Named and default parameters classRational(n: Int= 1, d: Int = 1) extendsAnyRef { .... } Rational(n = 2, d = 3) Rational(d = 3, n = 2) Rational(d = 3) Rational()
8. Object (Companion) objectRationalOneextends Rational(1) object Rational { def apply(n: Int) = new Rational(n) def apply(n: Int, d: Int) = new Rational(n, d) } valone = RationalOne valtwo = Rational(1) + one val two = Rational(1).+(one)
9. Traits classAnimal { defeat(): Unit } traitMammalextendsAnimal { defgiveBirth(): Mammal } traitHasWingsextendsAnimal { deffly(): Unit } traitHasLegsextendsAnimal { defwalk(): Unit } class Snake extendsAnimal classFrogextendsAnimal with HasLegs classCatextendsAnimalwithMammalwithHasLegs classBatextendsAnimalwithMammalwithHasWings class Chimera extendsAnimalwithMammalwithHasWingswithHasLegs
10. Let’s put alltogether trait IntSet { defcontains(x: Int): Boolean defnotContains(x: A) = !contains(x) defadd(x: Int): IntSet } object EmptySetextends IntSet { defcontains(x: Int): Boolean = false defadd(x: Int): IntSet = new NonEmptySet(x, EmptySet, EmptySet) } class NonEmptySet(elem: Int, left: IntSet, right: IntSet) extends IntSet{ defcontains(x: Int): Boolean = if (x < elem) left contains x else if (x > elem) right contains x else true defadd(x: Int): IntSet = if (x < elem) new NonEmptySet(elem, left add x, right) else if (x > elem) new NonEmptySet(elem, left, right add x) else this }
11. GenericTypes trait Set[A <: Ordered[A]] { def contains(x: A): Boolean def add(x: A): Set[A] } classEmptySet[A <: Ordered[A]] extends Set[A] { def contains(x: A): Boolean = false def add(x: A): Set[A] = new NonEmptySet(x, newEmptySet[A], newEmptySet[A]) } classNonEmptySet[A <: Ordered[A]] (elem: A, left: Set[A], right: Set[A]) extends Set[A] { def contains(x: A): Boolean = if (x < elem) left contains x else if (x > elem) right contains x elsetrue def add(x: A): Set[A] = if (x < elem) newNonEmptySet(elem, left add x, right) elseif (x > elem) newNonEmptySet(elem, left, right add x) elsethis }
12. Case classes sealed traitExpr case class Var(name: String) extendsExpr case class Number(num: Double) extendsExpr case class Unop(op: String, arg: Expr) extendsExpr case class Binop(op: String, l: Expr, r: Expr) extendsExpr
13. Pattern matching def simplify(expr: Expr): Expr = exprmatch { caseUnop("-", Unop("-", e)) => e // Double negation caseBinop("+", e, Number(0)) => e // Adding zero caseBinop("*", e, Number(1)) => e // Multiplying by one case _ => expr } // Simplify double negation: simplified = Var("x") val simplified = simplify(Unop("-", Unop("-", Var("x"))))
14. Tuples valpair = (2, "items") println(pair._1) // prints 2 println(pair._2) // printsitems defdivmod(x: Int, y: Int): (Int, Int) = (x / y, x % y) divmod(x, y) match { case (n, d) => println("quotient: " + n + ", rest: " + d) }
15. defsumInts(a: Int, b: Int): Int = if (a > b) 0 else a + sumInts(a + 1, b) defsumSquares(a: Int, b: Int): Int= if (a > b) 0 else a * a + sumSquares(a + 1, b) First-Class Function defsum(f: Int => Int, a: Int, b: Int): Int= if (a > b) 0 else f(a) + sum(f, a + 1, b) defid(x: Int): Int = x defsumInts(a: Int, b: Int): Int = sum(id, a, b) defsquare(x: Int): Int = x * x defsumSquares(a: Int, b: Int): Int = sum(square, a, b) Anonymous Function defsumInts(a: Int, b: Int): Int = sum((x: Int) => x, a, b) defsumSquares(a: Int, b: Int): Int = sum((x: Int) => x * x, a, b)
16. Higher-Order Functions and Curry defsum(f: Int => Int): (Int, Int) => Int = { defsumF(a: Int, b: Int): Int= if(a > b) 0 else f(a) + sumF(a + 1, b) sumF } defsumInts = sum(x => x) defsumSquares= sum(x => x * x) val sum1To10 = sumInts(1, 10) valsum1To10 = sum(x => x)(1, 10) def sum(f: Int => Int)(a: Int, b: Int): Int= if (a > b) 0 else f(a) + sum(f)(a + 1, b) def sum(a: Int, b: Int)(f: Int => Int): Int = if(a > b) 0 else f(a) + sum(a + 1, b)(f) valsum1To10 = sum(1, 10) { x => x }
17. Implicitparameters abstractclassAggregator[A] { defunit: A defadd(x: A, y: A): A } objectstringAggregatorextendsAggregator[String] { defunit= "" defadd(x: String, y: String): String = x concaty } objectintAggregatorextendsAggregator[Int] { defunit= 0 defadd(x: Int, y: Int): Int= x + y } def sum[A](l: List[A]) (a: Aggregator[A]): A = if (l.isEmpty) a.unitelsea.add(l.head, sum(l.tail)(a)) sum(List("a", "b", "c"))(stringAggregator) sum(List(1, 2, 3))(intAggregator) (implicit a: Aggregator[A]): A =
18. Implicitconversion val a = new Rational(2, 3) val b = a + 2 // = 8/3 val c = 2 + a // Compilation Error implicitdefintToRational(x: Int) = newRational(x) valc = 2 + a // = 8/3 Viewbound traitSet[A <% Rational]
19. Duck typing is the dynamic mechanism that allows to discover a dog cannot say quack only at runtime ... in production ... on friday evening Structural Typing (duck typing done right) doQuack(d) { d.quack() } defdoQuack(d:{ def quack():Unit }) = d.quack() classDuck { quack() { println "quack" } } doQuack(new Duck) classDuck { defquack() = println "quack" } doQuack(new Duck) class Dog { barf() { println "barf" } } doQuack(new Dog) class Dog { defbarf() = println "barf" } doQuack(new Dog) compilation error runtime error
20. Lists valletters: List[String] = List("a", "b", "c", "d") valemptyList = Nil valletters= "a" :: "b" :: "c" :: "d" :: Nil x :: ysisequivalent to ys.::(x) // infix operator == right associative xs ::: ysisequivalent toys.:::(xs) letters.head = "a" letters.tail = List("b", "c", "d") defsortedInsert(x: Int, xs: List[Int]): List[Int] = xsmatch { case List() => List(x) case y :: ys => if (x <= y) x :: xselse y :: sortedInsert(x, ys) }
22. For-Comprehensions for (p <- personsifp.age > 20) yield p.name personsfilter (p => p.age > 20) map (p => p.name) for { p <- persons // Generators c <- p.children if c.name startsWith"A" // Filter } yield p.name // Map
23. Given n>0 findallpairs iand j where 1 ≤j ≤ i ≤ n and i+jis prime List.range(1, n) .map(i => List.range(1, i).map(x => (i, x))) .foldRight(List[(Int, Int)]()) {(xs, ys) => xs ::: ys} .filter(pair => isPrime(pair._1 + pair._2)) List.range(1, n) .flatMap(i => List.range(1, i).map(x => (i, x))) .filter(pair => isPrime(pair._1 + pair._2)) Where: class List[A] { defflatMap[B](f: A => List[B]): List[B] } for { i <- List.range(1, n) j <- List.range(1, i) if isPrime(i + j) } yield {i, j} List.range(1, n) .flatMap(i => List.range(1, i) .filter(j => isPrime(i+j)) .map(j => (i, j)))
24. Tony Hoare, who invented the null reference in 1965 while working on an object oriented language called ALGOL W, called its invention his “billion dollar mistake” Options valcapitals = Map("Italy" -> "Rome", "Switzerland" -> "Bern", "Germany" -> "Berlin" , "France" -> "Paris") println(capitals.get("Italy")) // Some(Rome) println(capitals.get("Spain")) // None println(capitals.get("Italy").get) // Rome println(capitals.get("Spain").get) // thorwsException println(capitals.get("Spain").getOrElse("Unknown")) // Unknown
29. Creating Actors with the actormethod importscala.actors.Actor._ valprinterActor = actor { while(true) { receive { case s: String => println("I got a String: " + s) case i: Int => println("I got an Int: " + i.toString) case _ => println(" I don’t know what I got ") } } } printerActor ! "hi there" // prints “I got a String: hi there” printerActor ! 23 // prints “I got an Int: 23” printerActor ! 3.33 // prints “I don’t know what I got”
30. reactinstead of receive (whenpossible) importscala.actors.Actor._ valprinterActor = actor { loop { react { case s: String => println("I got a String: " + s) case i: Int => { println("I got an Int: " + i.toString) println(“Waiting for another Int") react { case j: Int=> println(“Another Int: " + j.toString) } } case _ => exit } } }
31. Message types ! send an asynchronous message which means that the sending actor does not wait until the message is received; its execution continues immediately. All actors have a mailbox which buffers incoming messages until they are processed !? senda synchronous message: causes the sending actor to wait until a response is received which is then returned. There is an overloaded variant taking a timeout and returning an Option[Any] instead of Any !! similar to !? In the sensethatitallows to get an answer from the receiver. However, instead of blocking the sending actor until a response is received, it returns Future instance that can be used to retrieve the receiver’s response once it is available
32. Remote Actors actor { // SERVER ACTOR RemoteActor.classLoader = getClass().getClassLoader() alive(9000) // starts remote actor listening on the given port register('Server, self) // registers the actor using the symbol loop { receive {case Message => sender ! ... } } } actor { // CLIENT ACTOR trapExit= true // listens exit of linked actors RemoteActor.classLoader= getClass().getClassLoader() alive(9001) valserver = select(Node("127.0.0.1", 9000), 'Server) link(server) // linksthisactor to the server one server ! Message // sends a Message to the server }