The document provides an overview of a two-day training course on Scala that covers topics like object orientation, functional programming, pattern matching, generics, traits, case classes, tuples, collections, concurrency, options and monads. The course aims to show how Scala combines object-oriented and functional programming approaches and provides examples of commonly used Scala features like classes, traits, pattern matching, generics and collections.
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 SimpleVs.Do More With Less
12. Case classessealed traitExprcase class Var(name: String) extendsExprcase class Number(num: Double) extendsExprcase class Unop(op: String, arg: Expr) extendsExprcase class Binop(op: String, l: Expr, r: Expr) extendsExpr
13. Pattern matchingdef simplify(expr: Expr): Expr = exprmatch {caseUnop("-", Unop("-", e)) => e // Double negationcaseBinop("+", e, Number(0)) => e // Adding zerocaseBinop("*", e, Number(1)) => e // Multiplying by onecase _ => expr}// Simplify double negation: simplified = Var("x")val simplified = simplify(Unop("-", Unop("-", Var("x"))))
14. Tuplesvalpair = (2, "items")println(pair._1) // prints 2println(pair._2) // printsitemsdefdivmod(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 Functiondefsum(f: Int => Int, a: Int, b: Int): Int= if (a > b) 0 else f(a) + sum(f, a + 1, b)defid(x: Int): Int = xdefsumInts(a: Int, b: Int): Int = sum(id, a, b)defsquare(x: Int): Int = x * xdefsumSquares(a: Int, b: Int): Int = sum(square, a, b)Anonymous FunctiondefsumInts(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 Currydefsum(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. ImplicitparametersabstractclassAggregator[A] {defunit: Adefadd(x: A, y: A): A}objectstringAggregatorextendsAggregator[String] {defunit= ""defadd(x: String, y: String): String = x concaty}objectintAggregatorextendsAggregator[Int] {defunit= 0defadd(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. Implicitconversionval a = new Rational(2, 3)val b = a + 2 // = 8/3val c = 2 + a // Compilation ErrorimplicitdefintToRational(x: Int) = newRational(x)valc = 2 + a // = 8/3ViewboundtraitSet[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 eveningStructural 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)compilationerrorruntime error
20. Listsvalletters: List[String] = List("a", "b", "c", "d")valemptyList = Nilvalletters= "a" :: "b" :: "c" :: "d" :: Nilx :: ysisequivalent to ys.::(x) // infix operator == right associativexs ::: 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)}
23. Given n>0 findallpairs iand j where 1 ≤j ≤ i ≤ n and i+jis primeList.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”Optionsvalcapitals = Map("Italy" -> "Rome", "Switzerland" -> "Bern", "Germany" -> "Berlin" , "France" -> "Paris")println(capitals.get("Italy")) // Some(Rome)println(capitals.get("Spain")) // Noneprintln(capitals.get("Italy").get) // Romeprintln(capitals.get("Spain").get) // thorwsExceptionprintln(capitals.get("Spain").getOrElse("Unknown")) // Unknown
29. Creating Actors with the actormethodimportscala.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 Actorsactor { // SERVER ACTORRemoteActor.classLoader = getClass().getClassLoader() alive(9000) // starts remote actor listening on the given port register('Server, self) // registers the actor using the symbolloop {receive {case Message => sender ! ... } }} actor { // CLIENT ACTORtrapExit= true // listens exit of linked actorsRemoteActor.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}