Scala - where objects and functions meet

  • 1,924 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • 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
    Your message goes here
No Downloads

Views

Total Views
1,924
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
36
Comments
1
Likes
3

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Whereobjects and functionsmeet
    by Mario Fusco
    mario.fusco@gmail.com
    twitter: @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 Simple
    Vs.
    Do More With Less
  • 4. statically typed
    object-oriented
    functional
    scriptable
    Why Scala?
    concise
    Java compatible
    extensible
    concurrent
  • 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()
  • 7. Scala’s type hierarchy
  • 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)
    }
  • 21. Higher-Order Functions on Lists
    valanimals = 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-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
  • 25. OptionsasMonads
    defmap[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 0
    defstringToInt(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 0
    valparams = Map("a" -> "5", "b" -> "false", "c" -> "-3")
    valreadPositiveIntParam(params, "a") // == 5
    valreadPositiveIntParam(params, "b") // == 0 – Samefor "c" and "d"
  • 26. Signals and Monitors
    defsynchronized[A] (e: => A): A
    defwait()
    defwait(msec: Long)
    defnotify()
    defnotifyAll()
    SyncVar
    class 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. Futures
    deffuture[A](p: => A): Unit => A = {
    valresult = new SyncVar[A]
    fork { result.set(p) }
    (() => result.get)
    }
    valx = future(someLengthyComputation)
    anotherLengthyComputation
    valy = f(x()) + g(x())
    Semaphores
    class Lock {
    varavailable = true
    defacquire = synchronized {
    while (!available) wait()
    available = false
    }
    defrelease = synchronized {
    available = true
    notify()
    }
    }
    Mailboxes
    class MailBox {
    defsend(msg: Any)
    defreceive[A](f: PartialFunction[Any, A]): A
    defreceiveWithin[A](msec: Long)(f: PartialFunction[Any, A]): A
    }
  • 28. Actors
    classPrinterActorextendsActor {
    defact() {
    while(true) {
    receive {
    casemsg=> println("Received message: " + msg)
    }
    }
    }
    }
    valprinterActor = newPrinterActor
    printerActor.start
    printerActor! "hi there“ // prints "Received message: hi there"
    printerActor ! 23 // prints "Received message: 23"
  • 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
    }