Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Scala - where objects and functions meet

2,997 views

Published on

Scala - where objects and functions meet

  1. 1. Whereobjects and functionsmeet<br />by Mario Fusco<br />mario.fusco@gmail.com<br />twitter: @mariofusco<br />
  2. 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 <br />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<br />
  3. 3. Do we need a new language?<br />Keep It Simple<br />Vs.<br />Do More With Less<br />
  4. 4. statically typed<br />object-oriented<br />functional<br />scriptable<br />Why Scala?<br />concise<br />Java compatible<br />extensible<br />concurrent<br />
  5. 5. The first Scala class<br />class Rational(n: Int, d: Int) {<br />valnum = n<br />val den = d<br />defthis(n: Int) = this(n, 1)<br />def + (that: Rational): Rational =<br />new Rational(num * that.den + that.num * den, den * that.den)<br />def + (i: Int): Rational = new Rational(num + i * den, den)<br />overridedeftoString = "" + num + "/" + den<br />}<br />
  6. 6. Named and default parameters<br />classRational(n: Int= 1, d: Int = 1) extendsAnyRef {<br /> ....<br />}<br />Rational(n = 2, d = 3)<br />Rational(d = 3, n = 2)<br />Rational(d = 3)<br />Rational()<br />
  7. 7. Scala’s type hierarchy<br />
  8. 8. Object<br />(Companion)<br />objectRationalOneextends Rational(1)<br />object Rational {<br />def apply(n: Int) = new Rational(n)<br />def apply(n: Int, d: Int) = new Rational(n, d)<br />}<br />valone = RationalOne<br />valtwo = Rational(1) + one <br />val two = Rational(1).+(one)<br />
  9. 9. Traits<br />classAnimal { defeat(): Unit }<br />traitMammalextendsAnimal { defgiveBirth(): Mammal }<br />traitHasWingsextendsAnimal { deffly(): Unit }<br />traitHasLegsextendsAnimal { defwalk(): Unit }<br />class Snake extendsAnimal<br />classFrogextendsAnimal with HasLegs<br />classCatextendsAnimalwithMammalwithHasLegs<br />classBatextendsAnimalwithMammalwithHasWings<br />class Chimera extendsAnimalwithMammalwithHasWingswithHasLegs<br />
  10. 10. Let’s put alltogether<br />trait IntSet {<br />defcontains(x: Int): Boolean<br />defnotContains(x: A) = !contains(x)<br />defadd(x: Int): IntSet<br />}<br />object EmptySetextends IntSet {<br />defcontains(x: Int): Boolean = false<br />defadd(x: Int): IntSet = new NonEmptySet(x, EmptySet, EmptySet)<br />}<br />class NonEmptySet(elem: Int, left: IntSet, right: IntSet) extends IntSet{<br />defcontains(x: Int): Boolean =<br /> if (x < elem) left contains x<br /> else if (x > elem) right contains x<br /> else true<br />defadd(x: Int): IntSet =<br /> if (x < elem) new NonEmptySet(elem, left add x, right)<br /> else if (x > elem) new NonEmptySet(elem, left, right add x)<br /> else this<br />}<br />
  11. 11. GenericTypes<br />trait Set[A <: Ordered[A]] {<br />def contains(x: A): Boolean<br />def add(x: A): Set[A]<br />}<br />classEmptySet[A <: Ordered[A]] extends Set[A] {<br />def contains(x: A): Boolean = false<br />def add(x: A): Set[A] =<br /> new NonEmptySet(x, newEmptySet[A], newEmptySet[A])<br />}<br />classNonEmptySet[A <: Ordered[A]]<br /> (elem: A, left: Set[A], right: Set[A]) extends Set[A] {<br />def contains(x: A): Boolean =<br />if (x < elem) left contains x<br />else if (x > elem) right contains x<br />elsetrue<br />def add(x: A): Set[A] =<br />if (x < elem) newNonEmptySet(elem, left add x, right)<br />elseif (x > elem) newNonEmptySet(elem, left, right add x)<br />elsethis<br />}<br />
  12. 12. Case classes<br />sealed traitExpr<br />case class Var(name: String) extendsExpr<br />case class Number(num: Double) extendsExpr<br />case class Unop(op: String, arg: Expr) extendsExpr<br />case class Binop(op: String, l: Expr, r: Expr) extendsExpr<br />
  13. 13. Pattern matching<br />def simplify(expr: Expr): Expr = exprmatch {<br />caseUnop("-", Unop("-", e)) => e // Double negation<br />caseBinop("+", e, Number(0)) => e // Adding zero<br />caseBinop("*", e, Number(1)) => e // Multiplying by one<br />case _ => expr<br />}<br />// Simplify double negation: simplified = Var("x")<br />val simplified = simplify(Unop("-", Unop("-", Var("x"))))<br />
  14. 14. Tuples<br />valpair = (2, "items")<br />println(pair._1) // prints 2<br />println(pair._2) // printsitems<br />defdivmod(x: Int, y: Int): (Int, Int) = (x / y, x % y)<br />divmod(x, y) match {<br />case (n, d) => println("quotient: " + n + ", rest: " + d)<br />}<br />
  15. 15. defsumInts(a: Int, b: Int): Int = if (a > b) 0 else a + sumInts(a + 1, b)<br />defsumSquares(a: Int, b: Int): Int= <br /> if (a > b) 0 else a * a + sumSquares(a + 1, b)<br />First-Class Function<br />defsum(f: Int => Int, a: Int, b: Int): Int= <br /> if (a > b) 0 else f(a) + sum(f, a + 1, b)<br />defid(x: Int): Int = x<br />defsumInts(a: Int, b: Int): Int = sum(id, a, b)<br />defsquare(x: Int): Int = x * x<br />defsumSquares(a: Int, b: Int): Int = sum(square, a, b)<br />Anonymous Function<br />defsumInts(a: Int, b: Int): Int = sum((x: Int) => x, a, b)<br />defsumSquares(a: Int, b: Int): Int = sum((x: Int) => x * x, a, b)<br />
  16. 16. Higher-Order Functions and Curry<br />defsum(f: Int => Int): (Int, Int) => Int = {<br />defsumF(a: Int, b: Int): Int= if(a > b) 0 else f(a) + sumF(a + 1, b)<br />sumF<br />}<br />defsumInts = sum(x => x)<br />defsumSquares= sum(x => x * x)<br />val sum1To10 = sumInts(1, 10)<br />valsum1To10 = sum(x => x)(1, 10)<br />def sum(f: Int => Int)(a: Int, b: Int): Int=<br />if (a > b) 0 else f(a) + sum(f)(a + 1, b)<br />def sum(a: Int, b: Int)(f: Int => Int): Int = <br />if(a > b) 0 else f(a) + sum(a + 1, b)(f)<br />valsum1To10 = sum(1, 10) { <br /> x => x <br />}<br />
  17. 17. Implicitparameters<br />abstractclassAggregator[A] {<br />defunit: A<br />defadd(x: A, y: A): A<br />}<br />objectstringAggregatorextendsAggregator[String] {<br />defunit= ""<br />defadd(x: String, y: String): String = x concaty<br />}<br />objectintAggregatorextendsAggregator[Int] {<br />defunit= 0<br />defadd(x: Int, y: Int): Int= x + y<br />}<br />def sum[A](l: List[A]) (a: Aggregator[A]): A =<br />if (l.isEmpty) a.unitelsea.add(l.head, sum(l.tail)(a))<br />sum(List("a", "b", "c"))(stringAggregator)<br />sum(List(1, 2, 3))(intAggregator)<br />(implicit a: Aggregator[A]): A =<br />
  18. 18. Implicitconversion<br />val a = new Rational(2, 3)<br />val b = a + 2 // = 8/3<br />val c = 2 + a // Compilation Error<br />implicitdefintToRational(x: Int) = newRational(x)<br />valc = 2 + a // = 8/3<br />Viewbound<br />traitSet[A <% Rational]<br />
  19. 19. Duck typing is the dynamic mechanism that allows to discover a dog cannot say quack only at runtime<br />... in production<br />... on friday evening<br />Structural Typing<br />(duck typing done right)<br />doQuack(d) { d.quack() }<br />defdoQuack(d:{ def quack():Unit }) =<br />d.quack()<br />classDuck { <br />quack() { println "quack" } <br />}<br />doQuack(new Duck)<br />classDuck { <br />defquack() = println "quack" <br />}<br />doQuack(new Duck)<br />class Dog { <br />barf() { println "barf" } <br />}<br />doQuack(new Dog)<br />class Dog { <br />defbarf() = println "barf" <br />}<br />doQuack(new Dog)<br />compilation<br />error<br />runtime error<br />
  20. 20. Lists<br />valletters: List[String] = List("a", "b", "c", "d")<br />valemptyList = Nil<br />valletters= "a" :: "b" :: "c" :: "d" :: Nil<br />x :: ysisequivalent to ys.::(x) // infix operator == right associative<br />xs ::: ysisequivalent toys.:::(xs)<br />letters.head = "a"<br />letters.tail = List("b", "c", "d")<br />defsortedInsert(x: Int, xs: List[Int]): List[Int] = xsmatch {<br />case List() => List(x)<br />case y :: ys => if (x <= y) x :: xselse y :: sortedInsert(x, ys)<br />}<br />
  21. 21. Higher-Order Functions on Lists<br />valanimals = List("dog", "cat", "horse", "rabbit")<br />animals.foreach(s => println(s))<br />defforeach(f: A => Unit) {<br />thismatch {<br />caseNil => ()<br />case x :: xs => f(x); xs.foreach(f) <br /> }<br />}<br />animals.foreach(println_)<br />animals.foreach(println)<br />animals.map(s => s + "s")<br />animals.mkString(", ")<br />animals.count(s => s.length > 3)<br />animals.remove(s => s.length > 3)<br />animals.sort((s,t) => s.charAt(1) < t.charAt(1))<br />animals.foldLeft(0)((s,t) => s + t.length)<br />(0 /: animals)(_ + _.length)<br />
  22. 22. For-Comprehensions<br />for (p <- personsifp.age > 20) yield p.name<br />personsfilter (p => p.age > 20) map (p => p.name)<br />for {<br /> p <- persons // Generators<br /> c <- p.children<br />if c.name startsWith"A" // Filter<br />} yield p.name // Map<br />
  23. 23. Given n>0 findallpairs iand j where 1 ≤j ≤ i ≤ n and i+jis prime<br />List.range(1, n)<br /> .map(i => List.range(1, i).map(x => (i, x)))<br /> .foldRight(List[(Int, Int)]()) {(xs, ys) => xs ::: ys}<br /> .filter(pair => isPrime(pair._1 + pair._2))<br />List.range(1, n)<br /> .flatMap(i => List.range(1, i).map(x => (i, x)))<br /> .filter(pair => isPrime(pair._1 + pair._2))<br />Where: class List[A] { defflatMap[B](f: A => List[B]): List[B] }<br />for { i <- List.range(1, n)<br /> j <- List.range(1, i)<br /> if isPrime(i + j) } yield {i, j}<br />List.range(1, n)<br /> .flatMap(i =><br />List.range(1, i)<br /> .filter(j => isPrime(i+j))<br /> .map(j => (i, j)))<br />
  24. 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”<br />Options<br />valcapitals = Map("Italy" -> "Rome", "Switzerland" -> "Bern", <br /> "Germany" -> "Berlin" , "France" -> "Paris")<br />println(capitals.get("Italy")) // Some(Rome)<br />println(capitals.get("Spain")) // None<br />println(capitals.get("Italy").get) // Rome<br />println(capitals.get("Spain").get) // thorwsException<br />println(capitals.get("Spain").getOrElse("Unknown")) // Unknown<br />
  25. 25. OptionsasMonads<br />defmap[B](f: A => B): M[B]<br />defflatMap[B](f: A => M[B]): M[B]<br />deffilter(p: A => Boolean): M[A]<br />defreadPositiveIntParam(params: Map[String, String], name: String): Int= <br />paramsgetnameflatMapstringToIntfilter (_ > 0) getOrElse 0<br />defstringToInt(string: String) : Option[Int] = try {<br /> Some(string.toInt)<br />} catch {<br /> case _ : java.lang.NumberFormatException => None<br />}<br />defreadPositiveIntParam(params: Map[String, String], name: String): Int =<br /> (for{ param<- paramsgetname; <br />value<- stringToInt(param) if (value > 0)<br /> } yieldvalue) getOrElse 0<br />valparams = Map("a" -> "5", "b" -> "false", "c" -> "-3")<br />valreadPositiveIntParam(params, "a") // == 5<br />valreadPositiveIntParam(params, "b") // == 0 – Samefor "c" and "d"<br />
  26. 26. Signals and Monitors<br />defsynchronized[A] (e: => A): A<br />defwait()<br />defwait(msec: Long)<br />defnotify()<br />defnotifyAll()<br />SyncVar<br />class SyncVar[A] {<br /> private var isDefined: Boolean = false<br /> private varvalue: A = _<br />defget = synchronized {<br /> while (!isDefined) wait()<br /> value<br /> }<br />defset(x: A) = synchronized {<br /> value = x; isDefined = true; notifyAll()<br /> }<br />defisSet: Boolean = synchronized { isDefined }<br />defunset = synchronized { isDefined= false }<br />}<br />
  27. 27. Futures<br />deffuture[A](p: => A): Unit => A = {<br />valresult = new SyncVar[A]<br /> fork { result.set(p) }<br /> (() => result.get)<br />}<br />valx = future(someLengthyComputation)<br />anotherLengthyComputation<br />valy = f(x()) + g(x())<br />Semaphores<br />class Lock {<br />varavailable = true<br />defacquire = synchronized {<br /> while (!available) wait()<br /> available = false<br /> }<br />defrelease = synchronized {<br /> available = true<br /> notify()<br /> }<br />}<br />Mailboxes<br />class MailBox {<br />defsend(msg: Any)<br />defreceive[A](f: PartialFunction[Any, A]): A<br />defreceiveWithin[A](msec: Long)(f: PartialFunction[Any, A]): A<br />}<br />
  28. 28. Actors<br />classPrinterActorextendsActor {<br />defact() {<br />while(true) {<br /> receive {<br />casemsg=> println("Received message: " + msg)<br /> }<br /> }<br /> }<br />}<br />valprinterActor = newPrinterActor<br />printerActor.start<br />printerActor! "hi there“ // prints "Received message: hi there"<br />printerActor ! 23 // prints "Received message: 23"<br />
  29. 29. Creating Actors with the actormethod<br />importscala.actors.Actor._<br />valprinterActor = actor {<br />while(true) {<br /> receive {<br />case s: String => println("I got a String: " + s)<br />case i: Int => println("I got an Int: " + i.toString)<br />case _ => println(" I don’t know what I got ")<br /> }<br /> }<br />}<br />printerActor ! "hi there" // prints “I got a String: hi there”<br />printerActor ! 23 // prints “I got an Int: 23”<br />printerActor ! 3.33 // prints “I don’t know what I got”<br />
  30. 30. reactinstead of receive (whenpossible)<br />importscala.actors.Actor._<br />valprinterActor = actor {<br /> loop {<br />react {<br />case s: String => println("I got a String: " + s)<br />case i: Int => {<br />println("I got an Int: " + i.toString)<br />println(“Waiting for another Int")<br />react {<br />case j: Int=> println(“Another Int: " + j.toString)<br /> }<br /> }<br />case _ => exit<br /> }<br /> }<br />}<br />
  31. 31. Message types<br />! 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<br />!? 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<br />!! 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<br />
  32. 32. Remote Actors<br />actor { // SERVER ACTOR<br />RemoteActor.classLoader = getClass().getClassLoader()<br /> alive(9000) // starts remote actor listening on the given port<br /> register('Server, self) // registers the actor using the symbol<br />loop {<br />receive {case Message => sender ! ... }<br /> }<br />} <br />actor { // CLIENT ACTOR<br />trapExit= true // listens exit of linked actors<br />RemoteActor.classLoader= getClass().getClassLoader()<br />alive(9001)<br />valserver = select(Node("127.0.0.1", 9000), 'Server)<br /> link(server) // linksthisactor to the server one<br /> server ! Message // sends a Message to the server<br />}<br />

×