Clinton R. Nixon
Viget Labs
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
Most of Scala isn't jarring.
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))
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.
#!/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
Foo.count instead of Foo.count())Methods can be called in one of two ways:
object.method(argument)object method argumentEverything's a object, so this is how arithmetic works.
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
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
val basename = FilenameUtils.getBaseName(file) val path = FilenameUtils.getFullPath(file)source
val and var are used to declare variablesval = immutable valuevar = mutable variableImmutable variables simplify concurrency tremendously. I find they help me eliminate bugs, as well.
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.)
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
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 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 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
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
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)
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.
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
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.
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
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
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
Pros:
Cons: