Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Whereobjects and functionsmeetby Mario Fuscomario.fusco@gmail.comtwitter: @mariofusco
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
Do we need a new language?Keep It SimpleVs.Do More With Less
statically typedobject-orientedfunctionalscriptableWhy Scala?conciseJava compatibleextensibleconcurrent
The first Scala classclass Rational(n: Int, d: Int) {valnum = nval den = ddefthis(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}
Named and default parametersclassRational(n: Int= 1, d: Int = 1) extendsAnyRef { ....}Rational(n = 2, d = 3)Rational(d = 3, n = 2)Rational(d = 3)Rational()
Scala’s type hierarchy
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 = RationalOnevaltwo = Rational(1) + one val two = Rational(1).+(one)
TraitsclassAnimal                  { defeat(): Unit }traitMammalextendsAnimal   { defgiveBirth(): Mammal }traitHasWingsextendsAnimal { deffly(): Unit }traitHasLegsextendsAnimal  { defwalk(): Unit }class Snake extendsAnimalclassFrogextendsAnimal with HasLegsclassCatextendsAnimalwithMammalwithHasLegsclassBatextendsAnimalwithMammalwithHasWingsclass Chimera extendsAnimalwithMammalwithHasWingswithHasLegs
Let’s put alltogethertrait IntSet {defcontains(x: Int): BooleandefnotContains(x: A) = !contains(x)defadd(x: Int): IntSet}object EmptySetextends IntSet {defcontains(x: Int): Boolean = falsedefadd(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 truedefadd(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}
GenericTypestrait Set[A <: Ordered[A]] {def contains(x: A): Booleandef add(x: A): Set[A]}classEmptySet[A <: Ordered[A]] extends Set[A] {def contains(x: A): Boolean = falsedef 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 xelse if (x > elem) right contains xelsetruedef add(x: A): Set[A] =if (x < elem) newNonEmptySet(elem, left add x, right)elseif (x > elem) newNonEmptySet(elem, left, right add x)elsethis}
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
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"))))
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)}
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)
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 }
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 =
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]
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
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)}
Higher-Order Functions on Listsvalanimals = List("dog", "cat", "horse", "rabbit")animals.foreach(s => println(s))defforeach(f: A => Unit) {thismatch {caseNil => ()case x :: xs => f(x); xs.foreach(f)  }}animals.foreach(println_)animals.foreach(println)animals.map(s => s + "s")animals.mkString(", ")animals.count(s => s.length > 3)animals.remove(s => s.length > 3)animals.sort((s,t) => s.charAt(1) < t.charAt(1))animals.foldLeft(0)((s,t) => s + t.length)(0 /: animals)(_ + _.length)
For-Comprehensionsfor (p <- personsifp.age > 20) yield p.namepersonsfilter (p => p.age > 20) map (p => p.name)for {  p <- persons			// Generators  c <- p.childrenif c.name startsWith"A" 	// Filter} yield p.name			// Map
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)))
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
OptionsasMonadsdefmap[B](f: A => B): M[B]defflatMap[B](f: A => M[B]): M[B]deffilter(p: A => Boolean): M[A]defreadPositiveIntParam(params: Map[String, String], name: String): Int= paramsgetnameflatMapstringToIntfilter (_ > 0) getOrElse 0defstringToInt(string: String) : Option[Int] = try {  Some(string.toInt)} catch {  case _ : java.lang.NumberFormatException => None}defreadPositiveIntParam(params: Map[String, String], name: String): Int =  (for{ param<- paramsgetname; value<- stringToInt(param) if (value > 0)  } yieldvalue) getOrElse 0valparams = Map("a" -> "5", "b" -> "false", "c" -> "-3")valreadPositiveIntParam(params, "a") // == 5valreadPositiveIntParam(params, "b") // == 0 – Samefor "c" and "d"
Signals and Monitorsdefsynchronized[A] (e: => A): Adefwait()defwait(msec: Long)defnotify()defnotifyAll()SyncVarclass SyncVar[A] {  private var isDefined: Boolean = false  private varvalue: A = _defget = synchronized {    while (!isDefined) wait()    value  }defset(x: A) = synchronized {    value = x; isDefined = true; notifyAll()  }defisSet: Boolean = synchronized { isDefined }defunset = synchronized { isDefined= false }}
Futuresdeffuture[A](p: => A): Unit => A = {valresult = new SyncVar[A]  fork { result.set(p) }  (() => result.get)}valx = future(someLengthyComputation)anotherLengthyComputationvaly = f(x()) + g(x())Semaphoresclass Lock {varavailable = truedefacquire = synchronized {    while (!available) wait()    available = false  }defrelease = synchronized {    available = true    notify()  }}Mailboxesclass MailBox {defsend(msg: Any)defreceive[A](f: PartialFunction[Any, A]): AdefreceiveWithin[A](msec: Long)(f: PartialFunction[Any, A]): A}
ActorsclassPrinterActorextendsActor {defact() {while(true) {  receive {casemsg=> println("Received message: " + msg)      }    } }}valprinterActor = newPrinterActorprinterActor.startprinterActor! "hi there“  // prints "Received message: hi there"printerActor ! 23          // prints "Received message: 23"
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”
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    }  }}
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
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}

More Related Content

Scala - where objects and functions meet

  • 1. Whereobjects and functionsmeetby Mario Fuscomario.fusco@gmail.comtwitter: @mariofusco
  • 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
  • 5. The first Scala classclass Rational(n: Int, d: Int) {valnum = nval den = ddefthis(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 parametersclassRational(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 = RationalOnevaltwo = Rational(1) + one val two = Rational(1).+(one)
  • 9. TraitsclassAnimal { defeat(): Unit }traitMammalextendsAnimal { defgiveBirth(): Mammal }traitHasWingsextendsAnimal { deffly(): Unit }traitHasLegsextendsAnimal { defwalk(): Unit }class Snake extendsAnimalclassFrogextendsAnimal with HasLegsclassCatextendsAnimalwithMammalwithHasLegsclassBatextendsAnimalwithMammalwithHasWingsclass Chimera extendsAnimalwithMammalwithHasWingswithHasLegs
  • 10. Let’s put alltogethertrait IntSet {defcontains(x: Int): BooleandefnotContains(x: A) = !contains(x)defadd(x: Int): IntSet}object EmptySetextends IntSet {defcontains(x: Int): Boolean = falsedefadd(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 truedefadd(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. GenericTypestrait Set[A <: Ordered[A]] {def contains(x: A): Booleandef add(x: A): Set[A]}classEmptySet[A <: Ordered[A]] extends Set[A] {def contains(x: A): Boolean = falsedef 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 xelse if (x > elem) right contains xelsetruedef 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 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)}
  • 21. Higher-Order Functions on Listsvalanimals = List("dog", "cat", "horse", "rabbit")animals.foreach(s => println(s))defforeach(f: A => Unit) {thismatch {caseNil => ()case x :: xs => f(x); xs.foreach(f) }}animals.foreach(println_)animals.foreach(println)animals.map(s => s + "s")animals.mkString(", ")animals.count(s => s.length > 3)animals.remove(s => s.length > 3)animals.sort((s,t) => s.charAt(1) < t.charAt(1))animals.foldLeft(0)((s,t) => s + t.length)(0 /: animals)(_ + _.length)
  • 22. For-Comprehensionsfor (p <- personsifp.age > 20) yield p.namepersonsfilter (p => p.age > 20) map (p => p.name)for { p <- persons // Generators c <- p.childrenif c.name startsWith"A" // Filter} yield p.name // Map
  • 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
  • 25. OptionsasMonadsdefmap[B](f: A => B): M[B]defflatMap[B](f: A => M[B]): M[B]deffilter(p: A => Boolean): M[A]defreadPositiveIntParam(params: Map[String, String], name: String): Int= paramsgetnameflatMapstringToIntfilter (_ > 0) getOrElse 0defstringToInt(string: String) : Option[Int] = try { Some(string.toInt)} catch { case _ : java.lang.NumberFormatException => None}defreadPositiveIntParam(params: Map[String, String], name: String): Int = (for{ param<- paramsgetname; value<- stringToInt(param) if (value > 0) } yieldvalue) getOrElse 0valparams = Map("a" -> "5", "b" -> "false", "c" -> "-3")valreadPositiveIntParam(params, "a") // == 5valreadPositiveIntParam(params, "b") // == 0 – Samefor "c" and "d"
  • 26. Signals and Monitorsdefsynchronized[A] (e: => A): Adefwait()defwait(msec: Long)defnotify()defnotifyAll()SyncVarclass SyncVar[A] { private var isDefined: Boolean = false private varvalue: A = _defget = synchronized { while (!isDefined) wait() value }defset(x: A) = synchronized { value = x; isDefined = true; notifyAll() }defisSet: Boolean = synchronized { isDefined }defunset = synchronized { isDefined= false }}
  • 27. Futuresdeffuture[A](p: => A): Unit => A = {valresult = new SyncVar[A] fork { result.set(p) } (() => result.get)}valx = future(someLengthyComputation)anotherLengthyComputationvaly = f(x()) + g(x())Semaphoresclass Lock {varavailable = truedefacquire = synchronized { while (!available) wait() available = false }defrelease = synchronized { available = true notify() }}Mailboxesclass MailBox {defsend(msg: Any)defreceive[A](f: PartialFunction[Any, A]): AdefreceiveWithin[A](msec: Long)(f: PartialFunction[Any, A]): A}
  • 28. ActorsclassPrinterActorextendsActor {defact() {while(true) { receive {casemsg=> println("Received message: " + msg) } } }}valprinterActor = newPrinterActorprinterActor.startprinterActor! "hi there“ // prints "Received message: hi there"printerActor ! 23 // prints "Received message: 23"
  • 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}