# Scala School
## Disclaimer The content of these slides is a modified/adapted version of Twitter's Scala School project: http://twitter.github.io/scala_school/ https://github.com/twitter/scala_school2 Twitter is commited to training their new hires in Scala and we think that's cool. We also think that Scala is cool and we want you to think that as well. Anyways, so credits goes to the guys at Twitter for building this material.
## Scala at Hopper At hopper, we're building the largest structured database of travel information. We tackle complex problems at large scales so we like to have the right tools so we can focus on those problems. * Started being used in 2011, only marginally/informally * Became 50/50 (with Java) in 2012 * Hopper is officially a "Scala shop" in 2013 * 100% of our new backend code is Scala * Java code being replaced as we replace components We've replaced several complex core components. Everytime, the process cut down the amount of code by at least half.
## Scala at Hopper Today, we use Scala everywhere * Hadoop M/R * Storm * RPC services * Web frontend tools (not the actual Web Application though) * Data Analytics * anywhere we can!
## About this class The first session will cover basics: syntax and concepts. The second session will be more hands-on. Today, we encourage you to follow along with your own interpreter so you can explore things on your own.
## Why Scala? * Expressive * First-class functions and closures * Concise * Type inference * Literal syntax for function creation * Java interoperability * Can reuse java libraries and tools * No performance penalty * benefits from 15 years of JVM development and optimization
## What Scala? Scala is a `sca`lable `la`nguage. It can scale as you need it to. This is Scala: class Hello { def greet(name : String) { println("Hi there " + name) } }

And this is Scala

Write unit tests almost literally with Specs2

class HelloWorldSpec extends Specification {

    "The 'Hello world' string" should {
      "contain 11 characters" in {
        "Hello world" must have size(11)
## And this is Scala A word count Map/Reduce job using Scoobi val lines = fromTextFile("hdfs://in/...") val counts = lines.flatMap(_.split(" ")) .map(word => (word, 1)) .groupByKey .combine(_+_) persist(counts.toTextFile("hdfs://out/...", overwrite=true))

And this is Scala

Query MongoDB using Rogue (from Foursquare)

 def update() = {
  VenueRole where (_.venueid eqs this.id) 
    and (_.userid eqs userid)
    modify (_.role_type setTo RoleType.manager) 

## And this is Scala Write BASIC in Scala!
object SquareRoot extends Baysick {
  def main(args: Array[String]) = {
    10 PRINT "Enter a number"
    20 INPUT 'n
    30 PRINT "Square root of " % "'n is " % SQRT('n)
    40 END

## How Scala? * Compiles to java bytecode * Works with any standard JVM * Or even some non-standard JVMs like Dalvik * Scala compiler written by author of Java compiler
## Think Scala Although Scala is simply a jar file on your classpath, it is not just a library or a nicer/cleaner Java. It is its own language that happens to be compatible with all the java ecosystem. To properly learn Scala, approach it with a fresh mind.
## Start the Interpreter Let's start the Scala REPL. Easiest way is to use `sbt`. apt-get install sbt or brew install sbt or git clone https://github.com/twitter/finagle.git && cd finagle Then start the `sbt console`. $ sbt console [...] Welcome to Scala version 2.8.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20). Type in expressions to have them evaluated. Type :help for more information. scala>
# Variables and Expressions
## Mutable Variables You can declare a variable `n` of type `Int` with initial value of `1 + 1` like so: var n: Int = 1 + 1 You can reassign `var` n = n + 1 But Scala has static typing, so you can't change a `var`'s type var s: String = "Hi!" n = s // doesn't compile s = n // doesn't compile
## Statements and Expressions We're all used to sequential execution of statements like this: import util.Random.nextBoolean var n: Int = 0 if (nextBoolean()) { println("randomly true") n = n + 1 } else { println("randomly false") n = n - 1 } But in Scala, it is more conventional to use control-flow structures as expressions: n = if(nextBoolean()) n + 1 else n - 1 and they compose var s: String = if (n % 2 == 0) "n is even: %d, half is: %d".format(n, n / 2) else "n is odd: %d, randomly fixing it: %d".format(n, if (nextBoolean()) n + 1 else n - 1)
## Immutable Values Given that expressions compose, mutable variables become less useful. It’s typically easiest to compute values by composing expressions rather than sequencing effects. So in Scala, we use `val`: val n: Int = 1 + 1 n = n + 1 // doesn't compile Sometimes `var` is necessary. Most of the time, it isn't.
## Equality Scala has both reference and value equality. val foo = "foobar" val bar = new String("foobar") foo == bar // true foo.eq(bar) // false
# Functions
## Functions You can create functions with def. scala> def addOne(m: Int): Int = m + 1 addOne: (m: Int)Int In Scala, you need to specify the type signature for function parameters. scala> val three = addOne(2) three: Int = 3
## Zero-Argument Functions You can leave off parens on functions with no arguments. scala> def three() = 1 + 2 three: ()Int scala> three() res2: Int = 3 scala> three res3: Int = 3
## Named and Default Arguments When calling a method, you can pass arguments in an arbitrary order by naming them: def formatUser(userId: Long, userName: String, realName: String): String = "%s <%d>: %s".format(userName, userId, realName) formatUser( realName = "Dan Rosen", userName = "drosen", userId = 31337 ) When defining a method, you can assign default values to some or all of its arguments. def formatUser( userId: Long = 0, userName: String = "unknown", realName: String = "Unknown" ): String = "%s <%d>: %s".format(userName, userId, realName) formatUser(userName = "drosen")
## Side-effecting functions and `Unit` Some functions are only used for their side-effects: scala> println("Hi!") Hi! In C-influenced languages, the result type would be `void`, representing the absence of a value. But the notion that some functions can produce a value and some can't introduces inconsistenty in the language. In order not to have this inconsistency, some languages, like Scala, introduce a type called `Unit` which has a single value `()`. So side-effecting functions can now return a value just like all the other ones: def noop() : Unit = () Side-effecting functions can be written like so: def noop() { }
## Anonymous Functions You can create anonymous functions. scala> (x: Int) => x + 1 res2: (Int) => Int = <function1> scala> res2(1) res3: Int = 2 You can pass anonymous functions around or save them into vals. scala> val addOne = (x: Int) => x + 1 addOne: (Int) => Int = <function1> scala> addOne(1) res4: Int = 2
## Big Functions If your function is made up of many expressions, you can use {} to give yourself some breathing room. def timesTwo(i: Int): Int = { println("hello world") i * 2 } This is also true of an anonymous function. val timesTwo = { i: Int => println("hello world") i * 2 }
## Partial application You can partially apply a function with an underscore, which gives you another function. Scala uses the underscore to mean different things in different contexts, but you can usually think of it as an unnamed magical wildcard. In the context of `{ _ + 2 }` it means an unnamed parameter. You can use it like so: scala> def adder(m: Int, n: Int) = m + n adder: (m: Int,n: Int)Int scala> val add2 = adder(2, _:Int) add2: (Int) => Int = <function1> scala> add2(3) res50: Int = 5 You can partially apply any argument in the argument list, not just the last one.
## Curried functions Sometimes it makes sense to let people apply some arguments to your function now and others later. Here's an example of a function with multiple argument lists: scala> def multiply(m: Int)(n: Int): Int = m * n multiply: (m: Int)(n: Int)Int You can call it directly with both arguments, or fill in the first and then the second. scala> multiply(2)(3) res0: Int = 6 scala> val timesTwo = multiply(2) _ timesTwo: (Int) => Int = <function1> scala> timesTwo(3) res1: Int = 6
## Aside: the underscore `_` Scala allows the use of the underscore as a wildcard in several places. It can be confusing when reading Scala at first. As a rule of thumb, it either means _whatever_ or _everything_. For example, using `_` within a single-argument function would mean _whatever the argument is_. Using it in an import statement would mean _everything from that package_.
## Variable length arguments There is a special syntax for methods that can take parameters of a repeated type. def countArgs(args: String*) = { args.size() } scala> countArgs("One", "Two", "Three") res0: Int = 3
# For-Expressions
## `while`- and `for`-loops We've all written this code in _some_ language at least once: var i = 0 while (i < 10) { println("I'M AWESOME") i = i + 1 } or more succinctly: for (i <- 0 until 10) println("I'M AWESOME")
## `for`-loops Maybe this is a bit more common: import collection.mutable.Buffer val quietWords = List("let's", "transform", "words") val noisyWords = Buffer.empty[String] for (i <- 0 until quietWords.size) noisyWords += quietWords(i).toUpperCase Although we're doing something very common, this code is extremely verbose (it's also terribly innefficient). * `quietWords` appears 3 times * `noisyWords` appears twice So we can do better: val noisyWords = Buffer.empty[String] for (word <- quietWords) noisyWords += word.toUpperCase No more explicit indexing, and we're now linear time, but...
## `for`-expressions The mutable `Buffer`-based approach is still dissatisfying. We've been doing very well treating control flow structures as value-producing expressions so far, so why not here? val noisyWords = for (word <- quietWords) yield word.toUpperCase Good! we're now refferring to `quierWords` and `noisyWords` only once. We've also gotten rid of the mutable `Buffer` (+1 for immutability). The `for-yield` expression indicates _transformation_: it directly produces a new collection, where each element is transformed from a corresponding element in the original collection. In many other programming languages, this is referred to as "list comprehensions."
One nice thing about `for`-loops and `for`-expressions is that they can contain multiple _generators_, producing a similar effect to nested loops: val salutations = for (hello <- List("hello", "greetings"); world <- List("world", "interwebs")) yield "%s %s!".format(hello, world) This syntax starts to get a bit clunky, the more generators you have, so Scala provides an alternative syntax: val salutations = for { hello <- List("hello", "greetings") world <- List("world", "interwebs") } yield "%s %s!".format(hello, world) This is a bit confusing-looking at first, since the braces look like they're delineating a block of statements. It's not difficult to get used to, though, and it's the recommended style when you have multiple generators.
## Assignments and filters You can also directly assign bindings (equivalent to `val`s) inside the `for { ... }`, not directly generated from elements in a collection: val salutations = for { hello <- List("hello", "greetings") world <- List("world", "interwebs") salutation = "%s %s!".format(hello, world) // assignment here! } yield salutation ... which isn't necessarily useful by itself, but becomes very handy when you need to _filter_ some of the results: val salutations = for { hello <- List("hello", "greetings") world <- List("world", "interwebs") salutation = "%s %s!".format(hello, world) if salutation.length < 20 // tl;dr } yield salutation
# Object-oriented constructs
## Classes scala> class Calculator { | val brand: String = "HP" | def add(m: Int, n: Int): Int = m + n | } defined class Calculator scala> val calc = new Calculator calc: Calculator = Calculator@e75a11 scala> calc.add(1, 2) res1: Int = 3 scala> calc.brand res2: String = "HP" Contained are examples are defining methods with def and fields with val. Methods are just functions that can access the state of the class.
## Constructor Constructors aren't special methods, they are the code outside of method definitions in your class. Use the `new` keyword to construct an instance. class Calculator(brand: String) { val color: String = if (brand == "HP") "black" else "white" def add(m: Int, n: Int): Int = m + n } scala> val calc = new Calculator("HP") calc: Calculator = Calculator@1e64cc4d scala> calc.color res0: String = black
## Expressions Our BasicCalculator example gave an example of how Scala is expression-oriented. The value color was bound based on an if/else expression. Scala is highly expression-oriented: most things are expressions rather than statements. scala> val notation = if(calc.color == "black") "reverse polish" else "infix" notation : java.lang.String = "reverse polish"
## Inheritance class ScientificCalculator(brand: String) extends Calculator(brand) { def log(m: Double, base: Double) = { math.log(m) / math.log(base) } }
## Overloading methods class EvenMoreScientificCalculator(brand: String) extends ScientificCalculator(brand) { def log(m: Int): Double = log(m, math.exp(1)) }
## Abstract Classes You can define an `abstract class`, a class that defines some methods but does not implement them. Instead, subclasses that extend the abstract class define these methods. You can't create an instance of an abstract class. scala> abstract class Shape { | def getArea():Int // subclass should define this | } defined class Shape scala> class Circle(r: Int) extends Shape { | def getArea():Int = { r * r * 3 } | } defined class Circle scala> val s = new Shape <console>:8: error: class Shape is abstract; cannot be instantiated val s = new Shape ^ scala> val c = new Circle(2) c: Circle = Circle@65c0035b
## Traits `trait`s are collections of fields and behaviors that you can extend or mixin to your classes. trait Car { val brand: String } trait Shiny { val shineRefraction: Int def computeShinyness(light: Double) = { shineRefraction * light } } class BMW extends Car { val brand = "BMW" } One class can extend several traits using the `with` keyword: class BMW extends Car with Shiny { val brand = "BMW" val shineRefraction = 12 }
## Type Parameters Functions can be generic and work on any type. Here's an example of a generic Cache. trait Cache[K, V] { def get(key: K): V def put(key: K, value: V) def delete(key: K) } Methods can also have type parameters introduced. def remove[K](key: K)
## apply methods apply methods give you a nice syntactic sugar for when a class has one main use. scala> class Bar { | def apply() = 0 | } defined class Bar scala> val bar = new Bar bar: Bar = Bar@47711479 scala> bar() res8: Int = 0
## Function Traits In Scala, functions are represented by a set of traits: `Function0` through `Function22`. val double = new Function1[Int, Int] { def apply(x: Int): Int = x * 2 } is equivalent to val double = { x: Int => x * 2}
## Objects Objects are like classes, but with a single instance. Often used for 'static' values. object Constants { val Pi = 3.14 // Close enough } Classes and Objects can have the same name. The object is called a 'Companion Object'. Here is a trivial example that removes the need to use `new` to create an instance. class Bar(foo: String) object Bar { def apply(foo: String) = new Bar(foo) }
## Packages You can organize your code inside of packages. package com.twitter.example class ExampleClass at the top of a file will declare everything in the file to be in that package.
## Imports In another package, you'd need to `import` that class. import com.twitter.example.ExampleClass You can import everything from a package by using the wildcard: import com.twitter.example._ You can rename symbols when importing into your local scope: import java.util.{List => UtilList}
## Package Objects You can create an object for your package. These can be used to delcare anything (traits, classes, functions, etc.) It is often used to declare functions, constants and type definitions, because these cannot be declared out of "thin air": they need to be attached to an object. package com.twitter package object example { val SomeConstant = 42 def theMeaningOfLifeTheUniverseAndEverything() = SomeConstant }
# Pattern Matching
## Pattern Matching One of the most useful parts of Scala. Matching on values: val times = 1 times match { case 1 => "one" case 2 => "two" case _ => "some other number" } The `_` in the last case statement is a wildcard; it matches everything. Otherwise, you will suffer a runtime error if you pass in a number that doesn't match.
## Matching with Guards times match { case i if i == 1 => "one" case i if i == 2 => "two" case _ => "some other number" } Notice how we captured the value in the variable `i`.
## Matching on type You can use `match` to handle values of different types differently. def bigger(o: Any): Any = o match { case i: Int if i < 0 => i - 1 case i: Int => i + 1 case d: Double if d < 0.0 => d - 0.1 case d: Double => d + 0.1 case text: String => text + "s" }
## Matching on class members Remember our calculator from earlier? Let's classify them according to type. Here's the painful way first: def calcType(calc: Calculator) = calc match { case _ if calc.brand == "hp" && calc.model == "20B" => "financial" case _ if calc.brand == "hp" && calc.model == "48G" => "scientific" case _ if calc.brand == "hp" && calc.model == "30B" => "business" case _ => "unknown" }
## Case Classes case classes are used to conveniently store and match on the contents of a class. You can construct them without using new. scala> case class Calculator(brand: String, model: String) defined class Calculator scala> val hp20b = Calculator("hp", "20b") hp20b: Calculator = Calculator(hp,20b) case classes automatically have equality and nice toString methods based on the constructor arguments. scala> val hp20b = Calculator("hp", "20b") hp20b: Calculator = Calculator(hp,20b) scala> val hp20B = Calculator("hp", "20b") hp20B: Calculator = Calculator(hp,20b) scala> hp20b == hp20B res6: Boolean = true case classes can have methods just like normal classes.
## Case Classes with pattern matching case classes are designed to be used with pattern matching. Let's simplify our calculator classifier example from earlier. val hp20b = Calculator("hp", "20B") val hp30b = Calculator("hp", "30B") def calcType(calc: Calculator) = calc match { case Calculator("hp", "20B") => "financial" case Calculator("hp", "48G") => "scientific" case Calculator("hp", "30B") => "business" case Calculator(ourBrand, ourModel) => "Calculator: %s %s is of unknown type".format(ourBrand, ourModel) } Other alternatives for that last match case Calculator(_, _) => "Calculator of unknown type" OR we could simply not specify that it's a Calculator at all. case _ => "Calculator of unknown type" OR we could re-bind the matched value with another name case c@Calculator(_, _) => "Calculator: %s of unknown type".format(c)
## Exceptions Exceptions are available in Scala via a try-catch-finally syntax that uses pattern matching. try { remoteCalculatorService.add(1, 2) } catch { case e: ServerIsDownException => log.error(e, "the remote calculator service is unavailable.") } finally { remoteCalculatorService.close() }
## Try-Catch Expressions `try`s are also expression-oriented val result: Int = try { remoteCalculatorService.add(1, 2) } catch { case e: ServerIsDownException => { log.error(e, "the remote calculator service is unavailable.") 0 } } finally { remoteCalculatorService.close() } Finally will be called after an exception has been handled and is not part of the expression.
# Collections
## Ordered Collections `List` and `Vector` are `Seq`uential (ordered) collections. `List` is a singly-linked list with efficient head access. scala> val numbers = List(1, 2, 3, 4) numbers: List[Int] = List(1, 2, 3, 4) `Vector` is an ordered sequence with efficient random access. scala> val numbers = Vector(1, 2, 3, 4) numbers: Vector[Int] = Vector(1, 2, 3, 4)
## `Set` Sets have no duplicates. scala> Set(1, 1, 2) res0: scala.collection.immutable.Set[Int] = Set(1, 2) scala> res0 contains 5 res1: Boolean = false
## Tuple A tuple groups together simple logical collections of items without using a class. scala> val hostPort = ("localhost", 80) hostPort: (String, Int) = (localhost, 80) They have accessors that are named by their position (which is 1-based rather than 0-based). scala> hostPort._1 res0: String = localhost scala> hostPort._2 res1: Int = 80

Tuples fit with pattern matching nicely. hostPort match { case ("localhost", port) => ... case (host, port) => ... } Tuple has some special sauce for making pairs: `->` scala> 1 -> 2 res0: (Int, Int) = (1,2)
## `Map` A standard key-value map. Map("one" -> 1, "two" -> 2) That looks like special syntax, but it's just a series of pairs. Map(("one", 1), ("two", 2))
## `Option` `Option` is a container that may or may not hold something. The basic interface for Option looks like: trait Option[T] { def isDefined: Boolean def get: T def getOrElse(t: T): T } `Option` itself is generic and has two subclasses: `Some[T]` or `None` Let's look at an example of how Option is used: `Map.get` uses `Option` for its return type. Option tells you that the method might not return what you're asking for. scala> val numbers = Map(1 -> "one", 2 -> "two") numbers: scala.collection.immutable.Map[Int,String] = Map((1,one), (2,two)) scala> numbers.get(2) res0: Option[java.lang.String] = Some(two) scala> numbers.get(3) res1: Option[java.lang.String] = None Now our data appears trapped in this `Option`. How do we work with it?
## `Option` (contd) A first instinct might be to do something conditionally based on the `isDefined` method. // We want to multiply the number by two, otherwise return 0. val result = if (res1.isDefined) { res1.get * 2 } else { 0 } We would suggest that you use either `getOrElse` or pattern matching to work with this result. `getOrElse` lets you easily define a default value. val result = res1.getOrElse(0) * 2 Pattern matching fits naturally with `Option`. val result = res1 match { case Some(n) => n * 2 case None => 0 }
## Functional 'Combinators' `List(1, 2, 3) map squared` applies the function `squared` to the elements of the the list, returning a new list, perhaps `List(1, 4, 9)`. We call operations like `map` combinators. (If you'd like a better definition, you might like [Explanation of combinators](http://stackoverflow.com/questions/7533837/explanation-of-combinators-for-the-working-man) on Stackoverflow.) Their most common use is on the standard data structures.
## `map` Evaluates a function over each element in the list, returning a list with the same number of elements. scala> numbers.map((i: Int) => i * 2) res0: List[Int] = List(2, 4, 6, 8) or pass in a partially evaluated function scala> def timesTwo(i: Int): Int = i * 2 timesTwo: (i: Int)Int scala> numbers.map(timesTwo _) res0: List[Int] = List(2, 4, 6, 8)
## `foreach` `foreach` is like map but returns nothing. It is intended for side-effects only. scala> numbers.foreach((i: Int) => println(i)) You can try to store the return in a value but it'll be of type Unit (i.e. void) scala> val doubled = numbers.foreach((i: Int) => i * 2) doubled: Unit = ()
## `filter` `filter` removes any elements where the function you pass in evaluates to false. Functions that return a Boolean are often called predicate functions. scala> numbers.filter((i: Int) => i % 2 == 0) res0: List[Int] = List(2, 4) scala> def isEven(i: Int): Boolean = i % 2 == 0 isEven: (i: Int)Boolean scala> numbers.filter(isEven) res2: List[Int] = List(2, 4)
## `zip` `zip` aggregates the contents of two lists into a single list of pairs. scala> List(1, 2, 3).zip(List("a", "b", "c")) res0: List[(Int, String)] = List((1,a), (2,b), (3,c)) `unzip` does the opposite. scala> res0.unzip res1: (List[Int], List[String]) = (List(1, 2, 3),List(a, b, c))
## `partition` `partition` splits a list based on where it falls with respect to a predicate function. scala> val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) scala> val (even, odd) = numbers.partition { _ %2 == 0 } even: List[Int] = List(2, 4, 6, 8, 10) odd: List[Int] = List(1, 3, 5, 7, 9))
## `find` `find` returns the first element of a collection that matches a predicate function (as an `Option`). scala> numbers.find((i: Int) => i > 5) res0: Option[Int] = Some(6)
## `drop` & `dropWhile` `drop` drops the first i elements scala> numbers.drop(5) res0: List[Int] = List(6, 7, 8, 9, 10) `dropWhile` removes the first elements that match a predicate function. For example, if we `dropWhile` odd numbers from our list of numbers, `1` gets dropped (but not `3` which is "shielded" by `2`). scala> numbers.dropWhile(_ % 2 != 0) res0: List[Int] = List(2, 3, 4, 5, 6, 7, 8, 9, 10)
## `foldLeft` scala> numbers.foldLeft(0)((m: Int, n: Int) => m + n) res0: Int = 55 0 is the starting value (Remember that numbers is a `List[Int]`), and m acts as an accumulator. Seen visually: scala> numbers.foldLeft(0) { (m: Int, n: Int) => println("m: " + m + " n: " + n); m + n } m: 0 n: 1 m: 1 n: 2 m: 3 n: 3 m: 6 n: 4 m: 10 n: 5 m: 15 n: 6 m: 21 n: 7 m: 28 n: 8 m: 36 n: 9 m: 45 n: 10 res0: Int = 55
## `foldRight` Is the same as `foldLeft` except it runs in the opposite direction. scala> numbers.foldRight(0) { (m: Int, n: Int) => println("m: " + m + " n: " + n); m + n } m: 10 n: 0 m: 9 n: 10 m: 8 n: 19 m: 7 n: 27 m: 6 n: 34 m: 5 n: 40 m: 4 n: 45 m: 3 n: 49 m: 2 n: 52 m: 1 n: 54 res0: Int = 55
## `flatten` `flatten` collapses one level of nested structure. scala> List(List(1, 2), List(3, 4)).flatten res0: List[Int] = List(1, 2, 3, 4)
## `flatMap` `flatMap` is a frequently used combinator that combines mapping and flattening. `flatMap` takes a function that works on the nested lists and then concatenates the results back together. scala> val nestedNumbers = List(List(1, 2), List(3, 4)) nestedNumbers: List[List[Int]] = List(List(1, 2), List(3, 4)) scala> nestedNumbers.flatMap(x => x.map(_ * 2)) res0: List[Int] = List(2, 4, 6, 8) Think of it as short-hand for mapping and then flattening: scala> nestedNumbers.map((x: List[Int]) => x.map(_ * 2)).flatten res1: List[Int] = List(2, 4, 6, 8)
## What about `Map`? Maps can be thought of as a collection of pairs, so all the collection methods work. scala> val extensions = Map("steve" -> 100, "bob" -> 101, "joe" -> 201) extensions: scala.collection.immutable.Map[String,Int] = Map((steve,100), (bob,101), (joe,201)) scala> extensions.filter { _._2 < 200 } res0: scala.collection.immutable.Map[String,Int] = Map((steve,100), (bob,101))
# More about Functions
## `andThen` `andThen` is used to chain the output of one function as the input to another. val trim = { str: String => str.trim } val toUpper = { str: String => str.toUpperCase } val cleanup = trim andThen toUpper scala> cleanup(" input string ") res0: String = INPUT STRING
## `PartialFunction` A Partial Function is a function that's only defined for certain values of the defined type. `isDefinedAt` is a method on PartialFunction that can be used to determine if the PartialFunction will accept a given argument. scala> val stars = new PartialFunction[Int, String] { def apply(n: Int) = "*" * n def isDefinedAt(n: Int) = n >= 0 } stars: PartialFunction[Int,String] = <function1> scala> stars.isDefinedAt(1) res0: Boolean = true scala> stars.isDefinedAt(-1) res1: Boolean = false
## `orElse` You can define a 'fallback' `PartialFunction` using the `orElse` method. scala> val wildcard: PartialFunction[Int, String] = { case _ => "something else" } wildcard: PartialFunction[Int,String] = <function1> scala> val partial = stars orElse wildcard partial: PartialFunction[Int,String] = <function1> scala> partial(5) res27: String = ***** scala> partial(-1) res28: String = something else
## The mystery of `case` A `case` statement is a partial function. It's defined if any of the match statements match. Since it's just a function, it can be used anywhere a function is used. scala> case class PhoneExt(name: String, ext: Int) defined class PhoneExt scala> val extensions = List(PhoneExt("steve", 100), PhoneExt("robey", 200)) extensions: List[PhoneExt] = List(PhoneExt(steve,100), PhoneExt(robey,200)) scala> extensions.filter { case PhoneExt(name, extension) => extension < 200 } res0: List[PhoneExt] = List(PhoneExt(steve,100))
# Types
## Types in Scala Scala's powerful type system allows for very rich expression. Some of its chief features are: * *parametric polymorphism*: roughly, generic programming * *(local) type inference*: roughly, why you needn't say `val i: Int = 12: Int` * *existential quantification*: roughly, defining something _for some_ unnamed type
## Scala's Type Hierarchy * Everything extends from `Any` * All 'primitives' extend from `AnyVal` (`Int`, `Float`, etc.) * Everything else extends from `AnyRef` (String, etc.) * `Nothing` extends from everything (and is the only class that may extend from both `AnyRef` and `AnyVal`)

![Scala Type System](http://joelabrahamsson.com/PageFiles/148/1310_1644.jpg) Credit: http://joelabrahamsson.com/learning-scala-part-eight-scalas-type-hierarchy-and-object-equality/
## Type inference A traditional objection to static typing is that it has much syntactic overhead. Scala alleviates this by providing _type inference_. We've seen this already: // Infers that x is of type Int val x = 128 // Infers that the return type is Int def plusOne(x: Int) = x + 1 The compiler will teach you which types it can infer and which ones it can't.
## Type Ascriptions Sometimes you want the compiler to infer some type in particular (eg. for API compatibility). You can use a type 'ascription' for this: scala> "hello!": AnyRef res0: AnyRef = hello! This will fail if the types don't match up: scala> "hello!": Int <console>:8: error: type mismatch; found : java.lang.String("hello!") required: Int
## Quantification Sometimes you do not care to be able to name a type variable, for example: scala> def count[A](l: List[A]) = l.size count: [A](List[A])Int Instead you can use "wildcards": scala> def count(l: List[_]) = l.size count: (List[_])Int
## Implicits If you mark a function or value as `implicit`, the compiler can use it to automatically satisfy some constraints. This is a powerful but tricky type-system feature. Implicit conversions will let you treat one type as if it were another type. scala> "Hello World".drop(2) res0: String = llo World Implicit parameters let the compiler 'fill in' some of the arguments automatically. scala> List(1,2,3,4).sum res0: Int = 10
## Resources * Scala School: http://twitter.github.io/scala_school/ * Effective Scala: http://twitter.github.io/effectivescala/ * Coursera: https://www.coursera.org/course/progfun