Upcoming SlideShare
×

Scala - where objects and functions meet

2,412 views

Published on

1 Comment
5 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Mario, thank you so much for your excellent presentation of Scala held in Padua during last meet of 'programmers in padua' and thank you also for the slide condivision!
Good luck for your new job in Germany... and for your family!
-- Francesco, a partecipant of ProgrmmmersInPadua

Are you sure you want to  Yes  No
Views
Total views
2,412
On SlideShare
0
From Embeds
0
Number of Embeds
166
Actions
Shares
0
43
1
Likes
5
Embeds 0
No embeds

No notes for slide

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 />