SlideShare a Scribd company logo
Scala @ BeJUG
 Luc Duponcheel
    ImagineJ
September 2, 2009
Introduction



  Chapter 0

 Introduction
Types




Scala is a (taste)fully typed language
Types




Scala supports generic types
Expressions




Scala is an expression oriented language
Objects




Scala is an pure object oriented language
Functions




Scala is a functional language
Scalable language



Scala is a scalable language
    Scala does not grow on a language basis
    Scala grows on a library basis
Usage



Chapter 1

 Usage
Expression evaluation: Double



scala> 1.2.*(2.3)
res0: Double = 2.76

scala> 1.2 * 2.3
res1: Double = 2.76
Expression evaluation: String



scala> "Hello world".substring(2,9)
res2: java.lang.String = llo wor

scala> "Hello world" substring (2,9)
res3: java.lang.String = llo wor
Function result




def plus(x: Int) = (y: Int) => y + x
Function result


scala> :l plus.scala
Loading plus.scala...
plus: (x: Int)(Int) => Int

scala> plus(1)
res0: (Int) => Int = <function1>
Apply plus(1)



scala> plus(1).apply(1)
res1: Int = 2

scala> plus(1)(1)
res2: Int = 2
Function parameter




def applyToZero[X](f: Int => X) = f(0)
Function parameter


scala> :l applyToZero.scala
Loading applyToZero.scala...
applyToZero: [X]((Int) => X)X

scala> applyToZero (x => x + 1)
res0: Int = 1
Function parameter and result




def twice[X](f: X => X)
 = (x: X) => f(f(x))
Function parameter and result


scala> :l twice.scala
Loading twice.scala...
twice: [X]((X) => X)(X) => X

scala> twice((x: Int) => x + 1)(0)
res0: Int = 2
Many parameter lists




def twice[X](f: X => X)(x: X) = f(f(x))
Function parameter and result


scala> :l twiceMany.scala
Loading twiceMany.scala...
twice: [X](f: (X) => X)(x: X)X

scala> twice((x: Int) => x + 1)(0)
res0: Int = 2
Placeholder syntax


scala> :l applyToZero.scala
Loading applyToZero.scala...
applyToZero: [X]((Int) => X)X

scala> applyToZero (_ + 1)
res0: Int = 1
Patterns



Chapter 2

 Patterns
Compositional reuse


Compositional reuse is reuse of
code fragments
the building blocks, starting from atomic ones
code templates
the containers into which the building blocks
can be plugged
Natural numbers and digits




type Nat = Int
type Dig = Int
Structural recursion

def structRec[A]
 (a: A, op: (Dig, A) => A) : Nat => A = {
 (n: Nat) =>
  if(n == 0) {
   a
  } else {
   op(n % 10, structRec(a, op)(n / 10))
  }
}
Using structural recursion


def sumOfDigits =
  structRec[Int](0, _ + _)

def hasDigit(d: Dig) =
  structRec[Boolean](false, _ == d || _)

def exists(p: Dig => Boolean) =
  structRec[Boolean](false, p(_) || _)
Using structural recursion


scala> sumOfDigits(1234)
res0: Int = 10

scala> hasDigit(2)(1234)
res1: Boolean = true

scala> exists(_ == 2)(1234)
res2: Boolean = true
unfoldAndThenFold

           6
 ---- | /              |
| dig = 3 + 3 = rec |
 -----------------------
        | 2 + 1           |
        |      /         |
        |    1 + 0        |
        |          /    |
        |        0      0 |
List of digits

     :
 /        
3          :
      /        
     2          :
           /        
          1          :
                /
               0
Sum of list of digits

     +
 /        
3          +
      /        
     2          +
           /        
          1          +
                /        
               0          0
Tail recursion

def tailRec[A]
 (a: A, op: (Dig, A) => A) : Nat => A = {
 (n: Nat) =>
  if(n == 0) {
   a
  } else {
   tailRec(op(n % 10, a), op)(n / 10)
  }
}
Using tail recursion


def sumOfDigits =
  tailRec[Int](0, _ + _)

def hasDigit(d: Dig) =
  tailRec[Boolean](false, _ == d || _)

def exists(p: Dig => Boolean) =
  tailRec[Boolean](false, p(_) || _)
Using tail recursion


scala> sumOfDigits(1234)
res0: Int = 10

scala> hasDigit(2)(1234)
res1: Boolean = true

scala> exists(_ == 2)(1234)
res2: Boolean = true
iterateAndAccumulate

     6 = rec
| /               |
| 0     6          |
|     /           |
|    1 + 5         |
|         ------------
|       2| + 3 = acc |
 --------| /          |
   | dig = 3 + 0      |
Control



Chapter 3

 Control
Conditional construct


def _if
 (cond: Boolean)
 (block: () => Unit)
 = cond match {
     case true => block()
     case false => ()
   }
Conditional expression


scala> :l if.scala
Loading if.scala...
_if: (Boolean)(() => Unit)Unit

scala> _if(Math.random<0.5)(() =>
     | println("ok")
     | )
ok
Loop construct


def _while
 (cond: () => Boolean)
 (block: () => Unit): Unit
 = if(cond()) {
     block()
     _while(cond)(block)
   }
Loop expression


scala> :l while.scala
Loading while.scala...
_while: (() => Boolean)(() => Unit)Unit

scala> _while(() => Math.random<0.5)(() =>
     | println ("ok")
     | )
ok
Conditional construct


def _if
 (cond: Boolean)
 (block: => Unit)
 = cond match {
     case true => block
     case false => ()
   }
Loop construct


def _while
 (cond: => Boolean)
 (block: => Unit): Unit
 = if(cond) {
     block
     _while(cond)(block)
   }
Conditional expression


scala> :l if_cbn.scala
Loading if_cbn.scala...
_if: (Boolean)(=> Unit)Unit

scala> _if(Math.random<0.5) {
     | println ("ok")
     | }
ok
Loop expression


scala> :l while_cbn.scala
Loading while_cbn.scala...
_while: (=> Boolean)(=> Unit)Unit

scala> _while(Math.random<0.5) {
     | println ("ok")
     | }
ok
Types



Chapter 4

 Types
Instance constants



class C {
 val re = 0.0
 val im = 0.0
}
Instance constants: usage


scala> :l complex01.scala
Loading complex01.scala...
defined class C

scala> new C
res0: C = C@151fe8a
toString



class C {
 // ...
 override def toString
  = re + " + " + im + "*" + "i"
}
toString: usage


scala> :l complex02.scala
Loading complex02.scala...
defined class C

scala> new C
res0: C = 0.0 + 0.0*i
Class parameters



class C(r: Double, i: Double) {
 val re = r
 val im = i
 // ...
}
Class parameters: usage


scala> :l complex03.scala
Loading complex03.scala...
defined class C

scala> new C(-1, -1)
res0: C = -1.0 + -1.0*i
toString again

override def toString = {
 val sgnim = if(im<0.0){" - "}else{" + "}
 val absim = if(im<0.0){ -im }else{ im }

 if(im == 0.0) { re + "" } else {
 if(re == 0.0) { im + "*i" } else {
 re + sgnim + absim + "*i" } }
}
toString again: usage

scala> :l complex04.scala
Loading complex04.scala...
defined class C

scala> new C(-1, -1)
res0: C = -1.0 - 1.0*i

scala> new C(-1, +1)
res1: C = -1.0 + 1.0*i
Additive operators

class C(r: Double, i: Double) {
 // ...
 def +(c: C) =
  new C(re + c.re, im + c.im)
 def -(c: C) =
  new C(re - c.re, im - c.im)
 // ...
}
Additive operators: usage

scala> :l complex05.scala
Loading complex05.scala...
defined class C

scala> new C(+1,+1) + new C(-3,+2)
res1: C = -2.0 + 3.0*i

scala> new C(+1,+1) - new C(-3,+2)
res2: C = 4.0 - 1.0*i
Multiplicative operators


// ...
def *(c: C) = new C(re*c.re - im*c.im,
 im*c.re + re*c.im)
def /(c: C) = {
 val d = c.re*c.re + c.im*c.im
 new C((re*c.re + im*c.im) / d,
  (im*c.re - re*c.im) / d) }
// ...
Multiplicative operators: usage

scala> :l complex06.scala
Loading complex06.scala...
defined class C

scala> new C(+1,+1) * new C(-3,+2)
res0: C = -5.0 - 1.0*i

scala> new C(-5,-1) / new C(-3,+2)
res1: C = 1.0 + 1.0*i
Negation operator



class C(r: Double, i: Double) {
 // ...
 def unary_- = new C(-re, -im)
 // ...
}
Negation operator: usage

scala> :l complex07.scala
Loading complex07.scala...
defined class C

scala> - new C(-5,-1)
res0: C = 5.0 + 1.0*i

scala> - new C(5,1)
res1: C = -5.0 - 1.0*i
The complex number i


class C(r: Double, i: Double) {
 // ...
}

object C {
 val i = new C(0.0, 1.0)
}
The complex number i: usage

scala> :l complex08.scala
Loading complex08.scala...
...

scala> import C.i
import C.i

scala> i * i
res0: C = -1.0
Converting Double

class C(r: Double, i: Double) {
 // ...
}

object C {
 //...
 implicit def toC(d: Double)
  = new C(d, 0.0)
}
Converting Double: usage

scala> :l complex09.scala
Loading complex09.scala...
...

scala> (1.0 + 1.0*i) / i
res0: C = 1.0 - 1.0*i

scala> 1.0 + 1.0*i / i
res1: C = 2.0
Spaces



Chapter 5

 Spaces
Space



class Space[X] extends Actor {
  // ...
}
Worker



abstract class Worker[X](space: Space[X])
 extends Actor {
  // ...
}
Work



object Types {
  type Work[X] = PartialFunction[X,Unit]
}
Put and Reg



case class Put[X](x: X)

case class Reg[X](
  work: Work[X]
  worker: Worker[X])
App




case class App[X](work: Work[X], x: X)
Space information




private var ps: List[Put[X]] = Nil
private var rs: List[Reg[X]] = Nil
Space functionality: part one



A worker can put objects x into the space
using space ! Put(x)
A worker can register work with the space
using space ! Reg(work, worker)
Space functionality: part two



A space can notify a worker when an object
x, to which the work he registered with the
space can be applied, has been put into the
space using worker ! App(work, x)
reacting to a Put: part one


case p@Put(x: X) => {
 val frs =
  rs filter(r => r.work.isDefinedAt(x)
 if(frs == Nil) {
  ps ::= p.asInstanceOf[Put[X]]
 }
reacting to a Put: part two



else {
 val fr = frs.last
 rs = rs filter (r => !(r eq fr))
 fr.worker ! App(fr.work, x)
}
reacting to a Reg: part one


case r@Reg(work, worker) => {
 val fps =
  ps filter (p => work.isDefinedAt(p.x))
 if(fps == Nil) {
  rs ::= r.asInstanceOf[Reg[X]]
 }
reacting to a Reg: part two



else {
 val fp = fps.last
 ps = ps filter (p => !(p eq fp))
 worker ! App(work, fp.x)
}
Worker: part one


abstract class Worker[X](space: Space[X])
 extends Actor {
  protected var isAcceptingMoreWork = true
  protected def registerForWork()
  def put(x: X) {
   space ! Put(x) }
  def reg(work: Work[X]) {
   space ! Reg(work, this) }
Worker: part two


private def applyZeroOrMoreTimes() {
 loop { react {
   case App(work, x) => {
    work.apply(x)
    if(isAcceptingMoreWork) {
     registerForWork()
    } } } }
}
Worker: part three



private def applyOneOrMoreTimes() {
 registerForWork()
 applyZeroOrMoreTimes()
}
Worker: part four



def act() {
 applyOneOrMoreTimes()
}
PingPong



sealed abstract class PingPong
 case object Ping extends PingPong
 case object Pong extends PingPong
 case object Over extends PingPong
 case object Done extends PingPong
Player


abstract class Player(
  name: String
  table: Space[PingPong]
)
extends Worker[PingPong](table) {
  override def toString = name
}
Pinger: part one

protected def registerForWork() =
reg {
 case Pong => {
  if (Math.random < 0.95) {
   println(this + " ping")
   put(Ping)
  } else {
   put(Over)
  }
Pinger: part two


   case Done => {
     println(this + " stop")
     isAcceptingMoreWork = false
   }
  }
 }
}
Ponger: part one

protected def registerForWork() =
reg {
 case Ping => {
  if (Math.random < 0.95) {
   println(this + " pong")
   put(Pong)
  } else {
   put(Over)
  }
Ponger: part two


   case Done => {
     println(this + " stop")
     isAcceptingMoreWork = false
   }
  }
 }
}
Umpire: part one


class Umpire(
 name: String,
 players: List[Player],
 table: Space[PingPong])
  extends Worker[PingPong](table) {
   override def toString = name
Umpire: part two

protected def registerForWork() =
reg {
  case Over => {
    println(this + " done")
    for { _ <- players } put(Done)
    println(this + " stop")
    isAcceptingMoreWork = false
  }
}
theTable



class Table extends Space[PingPong]

val theTable = new Table
thePlayers


val thePlayers =
 Pinger("pinger_1",   true) ::
 Pinger("pinger_2",   false) ::
 Ponger("ponger_1")   ::
 Ponger("ponger_2")   ::
 Nil
theUmpire



val theUmpire =
 new Umpire
  ("_umpire_", thePlayers, theTable)
main



theTable.start
thePlayers.foreach(_.start)
theUmpire.start
val startPinger = thePlayers.head
startPinger.put(Ping)

More Related Content

Scala by Luc Duponcheel