A presentation from Iulian Dragos of Typesafe that gives an overview of the Scala programming language. The presentation was given at a Functional Angle conference in Timisoara, Romania sponsored by 3Pillar. Iulian Dragos has been working on Scala since 2004. He currently works for Typesafe, a start-up that was co-founded by Scala’s creator, Martin Odersky.
2. What is Scala?
•A programming language running on the JVM
(also a JS backend)
•Statically typed, combines object-orientation
and functional programming
•Concise
•Fully interoperable with Java
•As fast as Java
2
4. Scala drives its social graph service:
380-400 M transactions/day
Migrated core messaging service
from Ruby to sustain 1000x growth
Approved for general production
use
Location-based social network. All
written in Scala (>5M users).
5
5. Philosophy
• “Growable language” (Guy Steele)
• embed DSLs/add new types
• Scalable language
• same concepts in small and large applications
• Deep rather than broad
• focus on abstraction and composition
6
6. public class Person {
public final String name;
public final int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
class Person(val name: String,
val age: Int)
Java
Scala
7
7. import java.util.ArrayList;
...
Person[] people;
Person[] minors;
Person[] adults;
{ ArrayList<Person> minorsList = new ArrayList<Person>();
ArrayList<Person> adultsList = new ArrayList<Person>();
for (int i = 0; i < people.length; i++)
(people[i].age < 18 ? minorsList : adultsList)
.add(people[i]);
minors = minorsList.toArray(people);
adults = adultsList.toArray(people);
}
val people: Array[Person]
val (minors, adults) = people partition (_.age < 18)
A tuple in a pattern match
Infix method call
Anonymous function
8
8. Overview
•Scala as an Object-Oriented Language
•Scala as a Functional Programming
Language
•Scala as a host language for DSLs
9
11. The bottom line
•Every value is an object
•Everything is an expression (evaluates to
a value)
•Every operation is a method call
•What about primitives?
12
12. type can be inferred
val x: Int = 10
val y = x + 10
same as x.+(10)
13
13. final class Int {
def +(y: Int): Int = <native>
def -(y: Int): Int = <native>
def *(y: Int): Int = <native>
def /(y: Int): Int = <native>
...
}
The compiler treats all primitives as if they were instances of
such classes (but uses primitive values for performance)
14
15. scala> val c = new Complex(1, 2)
c: test.Complex = 1 + 2i
scala> val c1 = new Complex(2, 2)
c1: test.Complex = 2 + 2i
scala> c + c1
res0: test.Complex = 3 + 4i
16
16. Everything is an
expression
•No statements
•Reduces the need for return and side-effects
17
17. def max(x: Int, y: Int) =
if (x > y) x else y
no return statement
scala> val t = {
| x = x + 10
| x - 1
| }
t: Int = 9
return type inferred to Int
blocks evaluate to last
expression
18
18. What about println?
scala> val x = println("hello, world")
hello, world
x: Unit = ()
The Unit type is like void in Java: no interesting value
19
20. Classes
•Similar to Java classes
•have fields, methods, parameters and
types
•every member can be overridden
•except classes (no virtual classes)
•any member can be abstract
21
21. explicit abstract class parameters/fields
abstract class Node[T](val v: T, next: Node[T])
extends List(v, next) {
val cache: Int
def first: T
def children = List(next)
override def toString = "Node " + v
}
22
super ctor call
When compiled, this class will look and behave exactly like the
obvious translation to a Java class. No glue code necessary.
22. Traits
•Like Java interfaces, but in addition
•allow concrete methods, fields, types
•Like Scala classes, but without
constructor parameters
•Allow (a form of) multiple inheritance
•mix-in composition
23
23. type parameter can extend Java classes
trait Ordered[A] extends java.lang.Comparable[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
}
classes mixing in Ordered will get all these methods ‘for free’
class Complex extends Ordered[Complex] {
def compare(that: Complex): Int = ...
}
24
24. if (c1 > c2) c1 else c2
val xs: List[Complex]
xs.sorted
25
26. Mix-in example: Cells
•model mutable cells that contain a single
value of some arbitrary type.
•Additionally, define logging and
undoable variants.
27
27. A class for generic cells
class Cell[T](val init: T) {
private var v = init
def get(): T = v
def set(v1: T): Unit = { v = v1 }
override def toString: String =
"Cell("+ v +")"
}
make init available as a field
mutable field
28
28. A trait for undoable cells
trait UndoableCell[T] extends Cell[T] {
import mutable.ArrayStack
private var hist = new ArrayStack[T]()
override def set(v1: T): Unit = {
hist.push(super.get())
super.set(v1)
}
def undo(): Unit =
super.set(hist pop)
}
29
29. A trait for logging cells
trait LoggingCell[T] extends Cell[T] {
override def get(): T = {
println("getting "+ this)
super.get()
}
override def set(v1: T): Unit = {
println("setting "+ this +" to "+ v1)
super.set(v1)
}
}
30
30. Mix-in composition
new Cell(0)
new Cell(0)
with LoggingCell[Int]
new Cell(0)
with LoggingCell[Int]
with UndoableCell[Int]
new Cell(0)
with UndoableCell[Int]
with LoggingCell[Int]
cell with logging
cell with logging
and undoing
cell with undoing
and logging
31
31. Mix-in composition
•traits can be stacked
•the call to super is dynamically bound
•super calls the ‘preceding’
implementation in the instantiated object
32
33. Modules
•Scala uses objects and traits for module
composition
•Composition through mixins
•Modules may require another module
34
34. Customers and DB
•Module Accounting
•requires a logger, a customer service
•Module Customers
•requires a logger, provides the
customer service
35
35. trait Accounting { this: Customers =>
val logger: Logger
customers.getCustomers // ..
}
trait Customers {
val logger: Logger
val customers: CustomerService
class CustomerService {
requires module Customers
def getCustomers: Unit = ()
//...
}
}
36
36. object App extends Accounting
with Customers {
val logger = // logback
val customers = new CustomerService
}
The application uses (some) concrete implementations of Accounting
and CustomerService.
37
37. This gives dependency
injection in the language!
object TestApp extends Accounting
with Customers {
val logger = // println based
val customers = new MockCustomerService
}
The test environment uses a mock CustomerService.
38
38. Summary
•Basic O-O features
•classes and traits
•type inference
•mix-in composition
•Advanced type system
•modules and dependencies
•dynamic binding of super
39
40. What is FP?
•Use of functions (in the mathematical sense)
•referential transparency (no side-effects)
•Immutable objects
•Functions are values
41
41. Scala as FPL
•function literals and closures
•use val instead of var
•immutable collections in the standard
library
•opt-in lazy evaluation
•curry-ing (definition site)
42
42. Function literals
scala> val succ = (x: Int) => x + 1
succ: (Int) => Int = <function1>
scala> succ(1)
res3: Int = 2
43
43. Equivalent forms
•x => x + 1 (infer type)
•1 + (partial application)
•_ + 1 (placeholder notation)
•compare _ (eta expansion)
44
45. val xs = List(1, 2, 3, 4, 5)
xs.foreach(println)
scala> xs.forall(_ < 10)
res5: Boolean = true
scala> xs.map(_ * 2)
res6: List[Int] = List(2, 4, 6, 8, 10)
def findBelow(limit: Int) =
persons.filter(_.age < limit)
lexical scoping: functions may refer and
even modify anything in scope
46
46. Everything is an object
•Closures are objects as well
•(compiler generated) instances of trait
Function1[A, B]
trait Function1[R, A] {
def apply(x: A): R
}
47
47. (More) sugar
•..but why can I call succ(10)?
•f(args) is desugared to f.apply(args)
•you can define your own ‘apply’
methods
•..can I subclass FunctionN?
48
48. Library
•Yes! Lots of collections are functions
•Sequences are Int => T
•Sets are T => Boolean
•Maps are K => V
49
53. For-comprehensions
may have any number of generators
p is in scope for other generators
for (p <- persons; pr <- p.projects;
if pr.overdue) yield p.name
guard construct a new collection of the same
type, element by element
res10: List[String] = List(“John”, “Harry”)
54
54. For-comprehensions
•Desugared to calls to filter, map, flatMap
•..any class implementing those methods
•Could be used to query a database
•implement filter, map, flatmap to
generate and forward SQL
•Slick, ScalaQuery, Squeryl
55
56. Pattern matching
•A way to deconstruct structured data
•A powerful switch statement (expression,
really)
57
57. Pattern matching
abstract class Expr
case class Literal(n: Int) extends Expr
case class Add(left: Expr, right: Expr)
extends Expr
case class Mul(left: Expr, right: Expr)
extends Expr the case modifier enables these classes
to participate in pattern matching
58
58. Pattern matching
def opt(e: Expr) = e match {
case Add(l, Literal(0)) => l
case Mul(l, Literal(1)) => l
case _ => e
}
patterns can be nested
literals match only their value
default case
59
59. Patterns everywhere
•Great way to process XML, JSON, etc.
•exception handlers are also patterns!
•..and also declarations
60
60. try {
//...
} catch {
case EvalError(line, msg) => //..
case e: IndexOutOfBoundsException => //..
}
61
62. Implicit conversions
•We can “grow” the language with
Complex numbers
•c + 1 works, but what about 1 + c?
63
63. Implicit conversions
•Allow user-defined conversions
•When the type does not have a member
•Find a method marked implicit that
takes the original type to one that has it
•Call the method implicitly
•It’s an error to have more than one
applicable conversions
64
64. implicit def intIsComplex(n: Int) =
new RichInt(n)
class RichInt(n: Int) {
def + (other: Complex) =
new Complex(n) + other
}
1 + c intIsComplex(1).+(c)
65
65. implicit class RichInt(n: Int) {
def + (other: Complex) =
new Complex(n) + other
}
Also a great way to adapt existing libraries
66
66. implicit class RichArray[T](as: Array[T]) {
def foreach(f: T => Unit) = ???
def map[U](f: T => U) = ???
def filter(f: T => Boolean) = ???
// ...
}
Scala arrays are Java arrays, but can still have the same API
67
67. Actor-based concurrency
•Threads and locks are error-prone
•(in fact, mutable shared data)
•Alternative: Message-passing with actors
•(no sharing)
•Implemented entirely in the library
•(3 other implementations out there)
68
68. Actors in Scala
actor ! msg
asynchronous message send
method call
receive {
case Ping(a1) => a1 ! msg
case Pong(_) => ..
}
Normal pattern match translated
to PartialFunction
69