Scala: A Modern Language

Clinton R. Nixon

Viget Labs

What's Scala?

Hello world

object HiThere {
  def main(args: Array[String]) {
    val name = if (args.isEmpty) "Developer Day" else args(0)
    println("Hi there, " + name)
  }
}

/*
$ scalac HiThere.scala
$ scala HiThere
Hi there, Developer Day
$ scala HiThere Durham
Hi there, Durham
*/
source

Why am I interested in Scala?

I'm a Javan:

Why am I interested in Scala?

I'm a Rubyist:

What is different about Scala?

Most of Scala isn't jarring.

Scala is a scripting language

Light ceremony in the REPL

scala> var pets = Map("dogs" -> List("Charlie", "Eli"), "cats" -> List("Violet"))
pets: scala.collection.immutable.Map[java.lang.String,List[java.lang.String]] = Map(dogs -> List(Charlie, Eli), cats -> List(Violet))

scala> pets("dogs").first                                                        
res2: java.lang.String = Charlie

scala> pets += ("unicorns" -> List("Spartacus"))

scala> pets
res5: scala.collection.immutable.Map[java.lang.String,List[java.lang.String]] = Map(dogs -> List(Charlie, Eli), cats -> List(Violet), unicorns -> List(Spartacus))

Type inference

class CSVLine(line: String) {
  val elements = line.split(",")

  def size = elements.size

  def apply(idx: Int) = {
    elements(idx)
  }

  def print {
    println(line)
  }
}
source

Only non-obvious cases need explicit typing.

Running a script

#!/bin/sh
exec scala $0 $@
!#

println(new String(args.deepMkString(" ").getBytes.map((b) => {
  if ((b >= 65 && b <= 77) || (b >= 97 && b <= 109))
    (b + 13).toByte
  else if ((b >= 78 && b <= 90) || (b >= 110 && b <= 122))
    (b - 13).toByte
  else
    b
})))

// > encrypt.scala I am Master Spy
// V nz Znfgre Fcl
source

Light syntax

Syntax made for DSLs

Methods can be called in one of two ways:

Everything's a object, so this is how arithmetic works.

An object created to make a DSL

class Trip {
  var startingWaypoint: Waypoint = null
  var currentWaypoint: Waypoint = null
  
  def from(place: String) = {
    startingWaypoint = new Waypoint(place)
    currentWaypoint = startingWaypoint
    this
  }
  
  def to(place: String) = {
    currentWaypoint.next = new Waypoint(place)
    currentWaypoint = currentWaypoint.next
    this
  }
  
source

The DSL at work

class TripTest extends FunSuite with ShouldMatchers {
  test("should be able to take a trip") {
    val myTrip = new Trip from "Durham, NC" to "Nowhere, WV" to "Detroit, MI" to "Nunavut"
    myTrip.stops should equal (4)
  }
}
// END dsltest
source

Scala is a functional language

Immutability

  val basename = FilenameUtils.getBaseName(file)
  val path = FilenameUtils.getFullPath(file)
source

Immutable variables simplify concurrency tremendously. I find they help me eliminate bugs, as well.

First-class functions

  val slides = slideText.split("[\r\n]+---+[\r\n]+").map(
    (text) => new Slide(this, text))
source

The benefit of first-class functions cannot be emphasized enough. Functions are objects, complete with literal syntax and the ability to be returned from other functions.

This is what makes Ruby, JavaScript, and Scheme awesome (among other things.)

Tail recursion

object Recursor {  
  def recurseTailCall(i: Int) {
    if (i > 10)
      throw new Exception
    else
      recurseTailCall(i + 1)
  }

  def recurseNonTailCall(i: Int):Int = {
    if (i > 10)
      throw new Exception
    else {
      val j = recurseNonTailCall(i + 1)
      j
    }
  }
}
source

Tail recursion, tested

import org.scalatest._

class RecursorTest extends FunSuite {
  test("non-tail calls blow up the stack") {
    try { Recursor.recurseNonTailCall(1) }
    catch {
      case ex => assert(
        ex.getStackTrace()(0).getMethodName == ex.getStackTrace()(1).getMethodName)
    }
  }

  test("tail calls are ninja") {
    try { Recursor.recurseTailCall(1) }
    catch {
      case ex => assert(
        ex.getStackTrace()(0).getMethodName != ex.getStackTrace()(1).getMethodName)
    }
  }
}
source

Pattern matching

Pattern matching is the case statement bitten by a radioactive lambda.

Pattern matching on tests:

  def descriptions: Seq[String] = { 
    options.map( (opt) => opt match {
      case x if ! x.canBeInvoked => x.description
      case x if x.gobbleNextArgument => x.shortopt + " <value> or " + x.longopt + " <value>: " + x.description
      case _ => opt.shortopt + " or " + opt.longopt + ": " + opt.description
    })
  }
source

Pattern matching

Pattern matching on equivalence:

    slideXML match {
      case <pre /> => 
        includeCode(slideXML)
      case Elem(_, _, _, _, c @ _ *) =>
        Elem(slideXML.prefix, 
             slideXML.label,
             slideXML.attributes,
             slideXML.scope,
             c.map((child) => processDirectives(child)): _*) // recursive
      case _ => slideXML
    }
source

Scala is an object-oriented language

Stand-alone and companion objects

object Slideshow {
  val doctype = DocType("html", 
                        PublicID("-//W3C//DTD XHTML 1.0 Strict//EN",
                                 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"), Nil)
  
  def create(filename: String) {
    val slideshow = new Slideshow(filename)
    slideshow.saveHTML()
  }
}

class Slideshow(file: String) {
source

Data structures

Most data structures are available in immutable and mutable flavors, and do the intelligent thing with similar methods.

scala> val mutableMap = scala.collection.mutable.Map("Durham" -> "awesome")

scala> mutableMap.update("Columbus", "not so great")                           

scala> mutableMap
res7: scala.collection.mutable.Map[java.lang.String,java.lang.String] = Map(Columbus -> not so great, Durham -> awesome)

scala> val immutableMap = scala.collection.immutable.Map("Durham" -> "awesome")

scala> immutableMap.update("Columbus", "not so great")                         
res8: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(Durham -> awesome, Columbus -> not so great)

Traits

class CSVLineTest extends FunSuite with ShouldMatchers {
  test("A CSVLine should split up a string") {
    val strings = List("a", "b", "c")
    val csvline = new CSVLine(strings.reduceLeft((a, b) => a + "," + b))
    csvline.size should equal (strings.size)
  }
}
source

Traits are like both Java interfaces and Ruby mixin modules. They can contain both concrete and abstract values and methods.

Multiple traits and traits at instantiation

class Dog { def bark = "WOOF" }
trait Ninja { def sneak = "..." }
trait Beggar { def beg = "MORAWR" }
class NinjaDog extends Dog with Ninja { }

val dog = new Dog
val ninjaDog = new NinjaDog
val myDog = new Dog with Ninja with Beggar

println(dog.bark)
println(ninjaDog.sneak)
println(myDog.beg)
println(myDog.sneak)

// WOOF
// ...
// MORAWR
// ...
source

Scala is a concurrent language

In Scala, actors pass messages to one another. These messages go into a queue to be handled later.

Messages are sent via the ! function: actor ! "message"

Messages are received via the receive or react methods.

Elevator example

This is how you would traditionally use concurrency in Java or most other languages.

class Floor {
  var loading = false
  var passengersWaiting = 0
  def waiting = passengersWaiting > 0

  def waitForElevator(msg: String) = synchronized {
    while (loading) wait()

    passengersWaiting += 1
    println(msg)

    notify()
  }
source

Actors on the elevator

Passenger sends a message to the floor:

class Passenger(building: Building, passengerNum: int) extends Actor {
  def act() = {
    val generator = new Random(passengerNum)
    def pickFloor() = 
      building.floor(generator.nextInt(building.topFloor) + 1)

    Thread.sleep(generator.nextInt(120 * 1000))

    val comingFrom = pickFloor()
    val goingTo = pickFloor()
    comingFrom ! (this, goingTo)
  }
source

Actors on the elevator

Floor reacts to the message:

class Floor(floorNum: int) extends Actor {
  private var passengersWaitingToGetOn = List[(Passenger, Floor)]()
  private var passengersWaitingToGetOff = List[Passenger]()
  
  def act() = {
    loop {
      react {
        case (passenger: Passenger, floor: Floor) =>
          passengersWaitingToGetOn = (passenger, floor) :: passengersWaitingToGetOn
          println(passenger + " waiting for elevator at " + this)
source

Scala is a modern language

Conclusion

Pros:

Cons:

Resources