A Taste of Scala

Presenter Notes

Me

Presenter Notes

Introduction

  • "Scalable Language"
  • Martin Odersky (1999 - 2003)
  • JVM (obviously)
  • "Multi-paradigm" programming language
  • Object Orientated
  • Functional
  • Statically typed

Presenter Notes

Hello World

object Main {
    def main(args:Array[String]) {
        println("Hello world")
    }
}

Note the of semi-colon

Presenter Notes

Companion Objects

  • Java
public class Main {

    private static String staticField;
    private String normalField;

    public static void main(String[] args) { }

    public void memberMethod() { }

    public static void utilMethod() { }
}

Presenter Notes

Companion Objects

  • Scala
object Main {
    var staticField:String;
    def main(args:Array[String]) {
        objectAsType(this)
    }

    def utilMethod() = {}

    def objectAsType(m:Main.type) = {
        m.utilMethod()
    }
}
class Main {
    var normalField;
    def memberMethod() = {}
}

Presenter Notes

Val vs Var

  • Emphasis on immutability in Scala
    • Better for concurrency
    • No locks
    • Easier to reason about
val s = "testing"
// Compile error
// s = "testing 2"
var s2 = "testing"
s2 = "testing 2" // OK

Presenter Notes

Type Inference

  • Java 7 - now with New and Improved™ diamond operator
List<Map<String, Map<String, String>>> listOfMaps = new ArrayList<>()
Map<String, Map<String, String>> mapOfMaps = listOfMaps.get(0)
Map<String, String> map = mapOfMaps.get("foo")
  • Scala
val listOfMaps = List(Map("a" -> Map("b" -> "c")))
val mapOfMaps = listOfMaps(0)
val map = mapOfMaps.get("foo").get
  • Not as good as Haskell (eg parameters always need types)
  • Often need types to help compiler

Presenter Notes

DSLs

  • Optional syntax
a.someMethod("one value");
a someMethod "one value"
a someMethod ("two", "values")
  • Unicode method names
    • not operator overloading
class Int {
    def +(b:Int) = ...
}
1 + 2 == 1.+(2)

Presenter Notes

DSL

  • Java 7 - now with New and Improved™ ARM block
try (FileInputStream in = new FileInputStream("foo.txt")) {
    // Do something
}
  • Last argument can be passed as block
def arm[C <: Closeable](closable: C)(f: (C) => Unit) = {
  try {
    f(closable)
  } finally {
    closable.close()
  }
}

arm(new FileInputStream("foo.txt")) { in =>
    // Do something
}

Presenter Notes

DSLs

  • Real world example - Gameboy Emulator
def accum(r1: Register, r2: Register) {
    r1.setValue(r2.getValue() << 4)
}
class Register(var value: Int) {
    def :=(i:Int) = { value = i }
    def <<(i: Int) = value << i
}

def accum(r1: Register, r2: Register) {
    r1 := r2 << 4
}

Presenter Notes

Inner defs

  • Java
public void someMethod() {
    helpMethod(1, 2)
    helpMethod(3, 4)
}

private int helpMethod(int i, int j) {
    return i + j
}
  • Relies on IDE to warn about unused methods
def someMethod = {
    def helpMethod(i: Int, j: Int) = i + j
    helpMethod(1, 2)
    helpMethod(3, 4)
}

Presenter Notes

Imports

  • Java
import java.util.List
import java.util.Map
import java.util.Set
  • Scala
import java.util.{List, Map, Set}
import java.util.{Collections => C}
import java.util.{Arrays => _}
import java.util._

def someMethod = {
    import java.util.ConcurrentMap
}

Presenter Notes

Default parameters

  • Java - who has written this?
public void method1(String a) {
    method1(a, 0)
}

public void method1(String a, int b) {
    method1(a, b, "")
}

public void method1(String a, int b, String c) {
    // Do something
}
  • Scala
def method1(a:String, b:Int = 0, c:String = "") = ...

method1("a")
method1("a", 1, "c")
method1("a", c = "c")
method1("a", c = "c", b = 1)
// etc

Presenter Notes

Functions

  • First class functions
val plus = (a:Int, b:Int) => a + b
val multi:Function2[Int, Int, Int] = (a:Int, b:Int) => a * b
plus(1, 2)
multi(2, 3)

def combine(f:(Int, Int) => Int) = f(2, 3)

combine(plus)
combine(multi)
combine((a:Int, b:Int) => a / b)
combine(_ + _)
combine(_ * _)

Presenter Notes

Functions

  • Every object is a function
object List {
    def apply(args:String*) = new List(args.toArray)
}
class List(args:Array[String]) {
    def apply(i:Int) = args(i)
}

val l = List("a", "b", "c")
val string = l(3)
val map = Map("a" -> "b")
val b = map("a")

Presenter Notes

Collections

  • Google Collections (Guava)
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
List<String> strings = Lists.transform(strings , new Function<String, Integer>() {
        @Override
        public String apply(Integer i) {
            return i + "";
        }
});

// Less lines of code
// Easier to read?
List<String> strings = new ArrayList<String>() {
for (Integer i : ints) {
    strings.add(i + "")
}

Presenter Notes

Collections

  • Scala has an amazing collections library
  • Immutable by default, otherwise import mutable package
val list = List(1, 2, 3, 4)
list.map((a:Int) => a + "")
list.map((a) => a + "")
list.map(_ + "")
list.map(_ + 1)
list.filter(_ > 2)
list.sort(_ > _)
list.reverse
list ++ list
val (small, big) = list partition (_ < 3)

val map = Map("a" -> "b")
map.mapElements(_ toUpperCase)
map.filterKeys(_ contains "x")
  • Powerful and easy parallel support
list.par map(_ + 1)
list.par filter(_ > 2)

Presenter Notes

Collections

  • For comprehensions
for (i <- List(1, 3, 4, 7)) {
    // do something
}

for (i <- 1 until 10) {
    // do something
}

for {
    i <- List(1, 3, 4, 7)
    j <- List(2, 4, 6, 8)
    if i + j > 3
} {
    // do something
}

Presenter Notes

Tuples

  • Returning two or more objects from a method
  • Have to create a 'temporary' class just for that method
public TempObject<String, Integer> returnSomething() = {
    return new TempObject("foo", 1);
}
TempObject<String, Integer> t = returnSomething(1);
t.first.substring(t.second);
  • Scala
def returnSomething(i:Int) = (i.toString, i)
val (a, b) = returnSomething(1)
// Type safe
a.substring(b)
val t = returnSomething(1)
t._1.substring(t._2)

Presenter Notes

Pattern Matching

  • Java 7 - now with New and Improved™ string switch/case
switch(string) {
    case "a": ... ; break;
    case "b": ... ; break;
    default: ...
}
  • Scala
string match {
    case "a" => ...
    case "b" => ...
    case _ => ...
}

No breaks

Presenter Notes

Pattern Matching

  • But wait, there's more
val t = (1, 2)
t match {
  case (2, _) => ...
  case (_, 3) => ...
  case (2, 4) | (1, 3) => ...
  case (a, b) if a == b => ...
  case (a, b) if a > b => ...
  case _ => ...
}

Presenter Notes

Traits

  • Analogous to interfaces, but can have implementation as well.
  • aka Mixins
  • Multiple inheritance
trait Ordered[A] {
    def compare(that: A): Int

    def <  (that: A): Boolean = (this compare that) <  0
    def >  (that: A): Boolean = (this compare that) >  0
    def <= (that: A): Boolean = (this compare that) <= 0
    def >= (that: A): Boolean = (this compare that) >= 0
}

class Something(val s:String) extends Ordered[String] {
    override compare(that:String) = s compare that
}

new Something("a") < "b"

Presenter Notes

Case Classes

public class Bean {
    private final int x;
    private final int y;

    public Bean(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int hashCode() {
        return x + y;
    }

    public String toString() {
        return "Bean(" + x + "," + y + ")";
    }
}

Presenter Notes

Case Classes

case class Bean(var x: Int, var y: Int)
val bean = new Bean(1, 2)
bean.x = 3
  • Free hashCode/toString methods
  • Free 'companion' object with apply
  • Can be used in pattern matching
val b = Bean(1, 2)
b match {
  case Bean(3, 4) => ...
  case Bean(a, b) if a == b => ...
  case _ => ...
}

Presenter Notes

Properties

  • What happens if you need to change behaviour of setter/getter?
case class Bean(private var _x: Int, var y: Int) {
  def x = _x
  def x_=(v: Int) { _x = v }
}
bean.x = 3

Presenter Notes

Death to null

Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();
Map<String, String> a = map.get("a");
if (a != null) {
    String b = a.get("b");
    if (b != null) {
        doSomething(b)
    }
}

Presenter Notes

Death to null

/**
 * May return null
 */
public String get(String key) {
    if (containsKey(value)) {
        return value;
    }
    return null;
}
  • Introducing Option (aka Maybe in Haskell)
  • Collection of None or Some element
def get(val:String):Option[String] = {
    if (containsKey(val)) {
        Some(value)
    } else {
        None // ie null
    }
}
  • Types as documentation
  • Much more powerful than @NotNull annotation

Presenter Notes

Death to null

  • Better?
val map = Map("a" -> Map("b" -> "c"))
val a = map.get("a")
if (a.isDefined) {
    val b = a.get.get("b")
    if (b.isDefined) {
        doSomething(b.get)
    }
}

Presenter Notes

Death to null

  • Only joking. :)
val map = Map("a" -> Map("b" -> "c"))
for (a <- map.get("a"); b <- a.get("b")) {
    doSomething(b)
}
  • Just a collection - lots of useful functions
val option:Option[String] = None
val string:String = option.getOrElse("a")
option.map(_ toUpperCase)
option.filter(_ contains "x")
option.foreach(println _)
  • Nulls are only needed in Scala for Java compatibility

Presenter Notes

Pimp my library

for (i <- 1 until 10) {
    // ...
}
  • 'until' is actually not defined on Int - RichInt
class RichInt(val i:Int) {
    def until(j:Int):Range[Int] = ...
}

implicit def int2rich(i:Int):RichInt = new RichInt(i)

for (i <- 1 until 10) ...

for (i <- int2rich(1).until(10)) ...
  • Searches the 'scope' for methods that return a type with missing method
  • Very useful - but use with care!

Presenter Notes

What's the catch?

  • Slow compiler

  • IDE support still lacking

  • Traits depend on compiled version of library
    • ie Causes binary incompatibility

Presenter Notes

Resources

Presenter Notes

Conclusion

  • Scala is like Java, only better
  • Much, much more - only scratched the surface
  • Full compatibility with Java
  • Start using it today!

Presenter Notes

Thank you

Presenter Notes