scala-logo.jpeg

Introduction to Scala

Scala is a modern language with a ton of excellent features. Definitely worth learning.

Overview

Scala

scalahipster.png

In Scala everything is an object, even numbers and functions.

Scala 2.9.1 was released on 2011-08-29.

Useful Links

Getting Started

Like most modern programming languages, you can execute programs stored in files or you can use the REPL (Read-Eval-Print Loop).

To use the REPL invoke scala with no arguments:

$ scala Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_24). Type in expressions to have them evaluated. Type :help for more information. scala> 3 + 7 * 8 res0: Int = 59 scala> "Programming languages".length res1: Int = 21 scala> def double(x: Int) = 2 * x double: (x: Int)Int scala> double(5) res2: Int = 10 scala> 3 < 5 < 20 <console>:8: error: type mismatch; found : Int(20) required: Boolean 3 < 5 < 20 ^ scala> 3 < 5 && 5 < 20 res4: Boolean = true scala> :quit $

You can put your script in a file, and invoke scala with the filename:

hello.scala
println("Hello, world")
$ scala hello.scala Hello, World

If you need commandline arguments, use the args array:

hellotoyou.scala
// Print a greeting for the one whose name is given as the first commandline argument.

print("Hello");
if (args.isEmpty || args(0).trim.isEmpty) {
  println
} else {
  println(", " + args(0))
}
$ scala hellotoyou.scala Hello $ scala hellotoyou.scala Alice Hello, Alice

Your script can also be comprised of an object with a method called main taking in an array of strings for the arguments:

codepoints.scala
object CodepointComputer {

  def codepointsFor(s: String) = {
    s.toList.map(c => c.toInt)
  }

  def main(args: Array[String]) {
    if (args.isEmpty || args(0).trim.isEmpty) {
      println("Missing argument")
    } else {
      println(codepointsFor(args(0)))
    }
  }
}

It works as before:

$ scala codepoints.scala dog List(100, 111, 103)

In addition, this style allows you to compile and interpret separately:

$ scalac codepoints.scala $ scala CodepointComputer dog List(100, 111, 103)
Exercise: Find out what files are produced by the scalac command above.

A Few Simple Scripts

Let's continue getting acquainted with the look and feel of Scala scripts:

today.scala
import java.util.{Date, Locale}
import java.text.DateFormat._

val now = new Date
val frenchDateForatter = getDateInstance(LONG, Locale.FRANCE)
println(frenchDateForatter format now)
println(getDateInstance(LONG, Locale.US) format now)
println(getDateInstance(SHORT, Locale.CHINA) format now)
fib.scala
// A script to write the Fibonacci numbers up to and including the first commandline argument.

object FibonacciLister {
  def main(args: Array[String]) {
    val n = args(0).toInt
    var (a, b) = (0, 1)
    while (b <= n) {
      print(b + " ")
      var olda = a
      a = b
      b = a + b
    }
    println
  }
}
timer.scala
object TimerExample {

  /**
   * Runs the passed in function pausing approximately one second in between calls,
   * as long as the function returns true.
   */
  def oncePerSecond(callback: () => Boolean) {
    while (callback()) {
      Thread sleep 1000
    }
  }

  /**
   * Counts down from 10 to 1, approximately once per second.
   */
  def main(args: Array[String]) {
    var count = 10;
    oncePerSecond(() => {println(count); count -= 1; count > 0})
  }
}

Types

Good terms to know:

Basic Types

TypeDescription
UnitHas only the single value ()
BooleanHas only the two values true and false
ByteThe 8-bit signed integers: -128...127
ShortThe 16-bit signed integers: -32768...32767
IntThe 32-bit signed integers: -2147483648...2147483647
LongThe 64-bit signed integers: -9223372036854775808..9223372036854775807
FloatThe 32-bit IEEE 754 floating point numbers
DoubleThe 64-bit IEEE 754 floating point numbers
CharThe Unicode characters with codepoints <= 0xFFFF
StringThe finite sequence of Char objects
NullHas only the single value null
NothingSubtype of every type
AnySupertype of every type
AnyRefSupertype of every reference type

Functions

functions.scala
import java.util.Arrays

def addSeven(x: Int) = x + 7
def multiplier(n: Int) = (x: Int) => x * n
def timesFour = multiplier(4)
def twice(f: (Int) => Int, x: Int) = f(f(x))
var timesThree = (x: Int) => x * 3
val collatz = (n: Int) => if (n % 2 == 0) n / 2 else 3 * n + 1

println(addSeven(5));
println(timesFour(10));
println(timesThree(10));

var n = 27
var a: Array[Int] = Array(n)
while (n != 1) {
  n = collatz(n)
  a ++= Array(n)
}
println(Arrays.toString(a))

Classes

Writing Classes

Here are a couple starter classes:

circle.scala
/**
 * A simple immutable circle with a center point and a radius.
 */
class Circle(x: Double, y: Double, radius: Double) {
  def center = (x, y)
  def area = math.Pi * radius * radius
  def perimeter = 2.0 * math.Pi * radius
  def move(dx: Double, dy: Double) = new Circle(x + dx, y + dy, radius)
  def expand(factor: Double) = new Circle(x, y, radius * factor)
  override def toString = "Circle at (" + x + "," + y + ") with radius " + radius
}
mutablecircle.scala
/**
 * A simple mutable circle with a center point and a radius.
 */
class MutableCircle(private var x: Double, private var y: Double, private var radius: Double) {

  def center = (x, y)

  def area = math.Pi * radius * radius

  def perimeter = 2.0 * math.Pi * radius

  def move(dx: Double, dy: Double) = {
    x += dx
    y += dy
    this
  }

  def expand(factor: Double) = {
    radius *= factor
    this
  }

  override def toString = "MutableCircle at (" + x + "," + y + ") with radius " + radius
}

Compile them, then let's see them in action:

scala> var c = new Circle(3, 5, 10) c: Circle = Circle at (3.0,5.0) with radius 10.0 scala> c.center res0: (Double, Double) = (3.0,5.0) scala> (c.area,c.perimeter) res1: (Double, Double) = (314.1592653589793,62.83185307179586) scala> c.move(4, 2) res2: Circle = Circle at (7.0,7.0) with radius 10.0 scala> c res3: Circle = Circle at (3.0,5.0) with radius 10.0 scala> c.move(5, 5).center res4: (Double, Double) = (8.0,10.0) scala> c.move(1, 1).expand(4).move(3, -8).area res5: Double = 5026.548245743669 scala> c.expand(0.5) res6: Circle = Circle at (3.0,5.0) with radius 5.0 scala> c res7: Circle = Circle at (3.0,5.0) with radius 10.0 scala> c.y <console>:9: error: value y is not a member of Circle c.y ^ scala> var mc = new MutableCircle(8, 2, 5) mc: MutableCircle = MutableCircle at (8.0,2.0) with radius 5.0 scala> mc.y <console>:9: error: variable y in class MutableCircle cannot be accessed in MutableCircle mc.y ^ scala> mc.center res11: (Double, Double) = (8.0,2.0) scala> mc.move(4, 2).expand(10) res12: MutableCircle = MutableCircle at (12.0,4.0) with radius 50.0 scala> mc res13: MutableCircle = MutableCircle at (12.0,4.0) with radius 50.0

Subclasses

Here's an abstract class for animals and three concrete subclasses.

animals.scala
abstract class Animal(name: String) {
  def speak = name + " says " + sound
  def sound: String
}

class Cow(name: String) extends Animal(name) {
  override def sound() = "moooooo"
}

class Horse(name: String) extends Animal(name) {
  override def sound() = "neigh"
}

class Sheep(name: String) extends Animal(name) {
  override def sound() = "baaaa"
}

var h = new Horse("CJ")
println(h.speak)
var c = new Cow("Bessie")
println(c.speak)
println(new Sheep("Little Lamb").speak)

Traits

Case Classes and Pattern Matching

Generics

Lists

Someone's blog post

For Comprehensions

A for comprehension is just syntactic sugar for certain (chains of) method calls. Examples are better than explanations here.

scala> val a = List(3, 6, 5, 7, 8, 1, 2, 3, 2, 14, 8)
a: List[Int] = List(3, 6, 5, 7, 8, 1, 2, 3, 2, 14, 8)

scala> a.map(x => x * 3)
res0: List[Int] = List(9, 18, 15, 21, 24, 3, 6, 9, 6, 42, 24)

scala> a.map(_ * 3)
res1: List[Int] = List(9, 18, 15, 21, 24, 3, 6, 9, 6, 42, 24)

scala> for (x <- a) yield x * 3
res2: List[Int] = List(9, 18, 15, 21, 24, 3, 6, 9, 6, 42, 24)

scala> a.filter(_ < 5).map(_ * 3)
res3: List[Int] = List(9, 3, 6, 9, 6)

scala> for (x <- a; if x < 5) yield x * 3
res4: List[Int] = List(9, 3, 6, 9, 6)

scala> a.filter(_ < 5).foreach(x => print(x * 3))
93696
scala> for (x <- a; if x < 5) {print(x * 3)}
93696
scala> for (x <- 0 until 4; y <- 0 until 4) yield (x, y)
res7: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((0,0), (0,1), (0,2), (0,3),
(1,0), (1,1), (1,2), (1,3), (2,0), (2,1), (2,2), (2,3), (3,0), (3,1), (3,2), (3,3))

scala> (0 until 4).flatMap(x => (0 until 4).map(y => (x, y)))
res8: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((0,0), (0,1), (0,2), (0,3),
(1,0), (1,1), (1,2), (1,3), (2,0), (2,1), (2,2), (2,3), (3,0), (3,1), (3,2), (3,3))

Mutable State

Streams

Lazy Values

Implicit Parameters

Concurrency

Unit Testing

Many unit testing frameworks exist for Scala. One of the most popular is ScalaTest. Start with the Quick Start. You'll want to start with FunSuite.

point.scala
class Point(val x: Double, val y: Double) {
  def distanceToOrigin() = math.sqrt(x * x + y * y);
  override def toString = "(" + x + "," + y + ")"
}
pointtest.scala
import org.scalatest.FunSuite

class PointSuite extends FunSuite {

  test("construction") {
    val p = new Point(3, -4)
    assert(p.x === 3)
    assert(p.y === -4)
  }

  test("making strings") {
    val p = new Point(3, -4)
    assert(p.toString() === "(3.0,-4.0)")
  }

  test("distance to origin") {
    val p = new Point(3, -4)
    assert(p.distanceToOrigin() === 5)
  }
}

To run:

$ scalac -cp scalatest-1.6.1.jar point.scala pointtest.scala
$ scala -cp scalatest-1.6.1.jar org.scalatest.tools.Runner -p . -o -s PointSuite

Language and Library Reference

In Scala 2.9.1, there are 57 packages in the Scala Standard Library.

PackageDescription
scalaCore Scala types. They are always available without an explicit import.
scala.actorsA library that provides both asynchronous and synchronous messaging to allow for concurrent programming without explicit synchronization.
scala.actors.remote
scala.actors.scheduler...
scala.annotation...
scala.annotation.target...
scala.annotation.unchecked...
scala.collectionContains the base traits and objects needed to use and extend Scala's collection library.
scala.collection.generic...
scala.collection.immutable...
scala.collection.interfaces...
scala.collection.mutable...
scala.collection.parallel...
scala.collection.parallel.immutable...
scala.collection.parallel.mutable...
scala.collection.script...
scala.compat...
scala.concurrent...
scala.io...
scala.math...
scala.parallel...
scala.ref...
scala.reflect...
scala.reflect.generic...
scala.runtime...
scala.swing...
scala.swing.event...
scala.swing.model...
scala.sys...
scala.sys.process...
scala.testing...
scala.text...
scala.util...
scala.util.automata...
scala.util.continuations...
scala.util.control...
scala.util.grammar...
scala.util.logging...
scala.util.matching...
scala.util.parsing.ast...
scala.util.parsing.combinator...
scala.util.parsing.combinator.lexical...
scala.util.parsing.combinator.syntactical...
scala.util.parsing.combinator.testing...
scala.util.parsing.combinator.token...
scala.util.parsing.input...
scala.util.parsing.json...
scala.util.regexp...
scala.xml...
scala.xml.dtd...
scala.xml.factory...
scala.xml.include...
scala.xml.include.sax...
scala.xml.parsing...
scala.xml.persistent...
scala.xml.pull...
scala.xml.transform...