Scala is a general purpose programming language designed to express common programming patterns in a concise, elegant, and type-safe way. It has established itself as one of the main alternative languages on the Java Virtual Machine, being used by companies like Twitter and LinkedIn. Scala fuses functional programming (from which it borrows higher-order functions and closures, generic typing and immutable data structures) and object-oriented programming programming (from which it takes inheritance and encapsulation). It interoperates fully with Java, allowing a smooth transition and access to all existing Java libraries.
Scala’s lightweight syntax makes it easy to extend the language through DSLs. In this talk we are going to have a quick overview of Scala’s main features (closures, higher-order functions, implicits), and collection classes in the standard library. We’ll see how a new concurrency model, such as actors, can be added to the language through a library.
2. What is Scala
A programming language that
• combines functional programming and object-oriented
programming
• is statically typed yet concise
• runs on the JVM and is fully interoperable with Java
• as fast as Java
• created at EPFL by Martin Odersky
2
3. Where it comes from
Scala has established itself as one of the main alternative languages
on the JVM.
Prehistory:
1996 – 1997: Pizza
1998 – 2000: GJ, Java generics, javac
( “make Java better” )
Timeline:
2003 – 2006: The Scala “Experiment”
2006 – 2009: An industrial strength programming language
( “make a better Java” )
3
4. Momentum
Open-source language with
Site scala-lang.org: 100K+ visitors/month
40,000 downloads/month, 10x growth last year
16 books in print
Two conferences: Scala Liftoff and ScalaDays
33+ active user groups
60% USA, 30% Europe, 10% rest
4
9. A class ...
public
class
Person
{
public
final
String
name;
public
final
int
age;
Person(String
name,
int
age)
{
this.name
=
name;
... in Java:
this.age
=
age;
}
}
class
Person(val
name:
String,
... in Scala:
val
age:
Int)
9
10. ... and its usage
import
java.util.ArrayList;
...
Person[]
people;
Person[]
minors;
Person[]
adults;
{
ArrayList<Person>
minorsList
=
new
ArrayList<Person>();
ArrayList<Person>
adultsList
=
new
ArrayList<Person>();
... in Java:
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);
}
A function value
An infix method call
... in Scala: val
people:
Array[Person]
val
(minors,
adults)
=
people
partition
(_.age
<
18)
A simple pattern match 10
11. Functions
Scala has first-class functions (closures)
val
f
=
(x:
Int)
=>
x
*
x
x
=>
x
*
x
and you can call them using
f.apply(4)
or f(4)
11
13. For-comprehensions
More than a simple for loop
for
(x
<-‐
xs)
println(x)
==
xs.foreach(println)
for
(x
<-‐
xs)
yield
x
*
x
==
xs.map(x
=>
x
*
x)
generator guard
for
(p
<-‐
ps
if
p.age
>
18)
yield
(p.age,
p)
ps.filter(_.age
>
18).map(p
=>
(p.age,
p))
13
15. Traits
Like Java interfaces, but may have concrete methods
trait
Ordered[T]
{
def
compare(that:
T):
Int
abstract method
def
<
(that:
T):
Boolean
=
(this
compare
that)
<
0
def
<=(that:
T):
Boolean
=
(this
compare
that)
<=
0
…
}
15
16. Cells
Let’s define a class for mutable cells
– with variants for logging and undoable cells.
16
17. Cells
class
Cell[T](init:
T)
{
private
var
v
=
init
def
get():
T
=
v
def
set(v1:
T):
Unit
=
{
v
=
v1
}
override
def
toString:
String
=
"Cell("+
v
+")”
}
17
19. Undoing
trait
UndoableCell[T]
extends
Cell[T]
{
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)
}
19
20. Mix-in composition
new
Cell(0)
//
basic
integer
cell
new
Cell(0)
with
LoggingCell[Int]
//
logging
cell
new
Cell(0)
with
LoggingCell[Int]
//
logging
and
undoing
with
UndoableCell[Int]
new
Cell(0)
with
UndoableCell[Int]
//
logging
and
undoing
with
LoggingCell[Int]
20
22. Embedding Domain-Specific Languages
Scala’s flexible syntax makes it //
asynchronous
message
send
easy to define
actor
!
message
high-level APIs &
embedded DSLs
//
message
receive
Examples: receive
{
- Scala actors (the core of
case
msgpat1
=>
action1
Twitter’s message queues)
…
- specs, ScalaCheck
case
msgpatn
=>
actionn
- ScalaFX }
- ScalaQuery
scalac’s plugin architecture makes it easy to typecheck DSLs and to
enrich their semantics.
22
23. The Essence of Scala
The work on Scala was motivated by two
hypotheses:
Hypothesis 1: A general-purpose language needs
to be scalable; the same concepts should describe
small as well as large parts.
Hypothesis 2: Scalability can be achieved by
unifying and generalizing functional and object-
oriented programming concepts.
23
24. Why unify FP and OOP?
Both have complementary strengths for composition:
Functional programming: Object-oriented programming:
Makes it easy to build interesting Makes it easy to adapt and extend
things from simple parts, using complex systems, using
• higher-order functions, • subtyping and inheritance,
• algebraic types and • dynamic configurations,
pattern matching,
• classes as partial abstractions.
• parametric polymorphism.
24
25. Scala
• Scala is an object-oriented and functional language
which is completely interoperable with Java.
(the .NET version is currently under
reconstruction.)
• It removes some of the more arcane constructs of
these environments and adds instead:
(1) a uniform object model,
(2) pattern matching and higher-order
functions,
(3) novel ways to abstract and compose
programs.
25
26. Scala is interoperable
object instead instead of
Array[String] of
static members
String[]
Scala programs interoperate
seamlessly with Java class object Example1 {
libraries: def main(args: Array[String]) {
– Method calls
val b = new StringBuilder()
– Field accesses
for (i ← 0 until args.length) {
– Class inheritance
if (i > 0) b.append(" ")
– Interface implementation
b.append(args(i).toUpperCase)
all work as in Java.
}
Scala programs compile to JVM
bytecodes. Console.println(b.toString)
}
Scala’s syntax resembles Java’s, }
but there are also some the extended
Scala’s version of
differences. for loop Arrays are indexed args
(use <- as an alias for ←) (i) instead of args[i]
26
27. Scala is functional
Arrays are instancesArray which
map is a method of of sequences
with map and mkString its right
applies the function on methods.
The last program can also to each array element.
be written in a completely object Example2 {
different style: def main(args: Array[String]) {
– Treat arrays as instances of println(args
general sequence abstractions. .map(_.toUpperCase)
– Use higher-order .mkString(" ")
functions instead of loops. }
}
A closure which applies the
mkString is a method of Array which to its
toUpperCase method
forms a string of all elementsargument
String with a
given separator between them.
27
28. Scala is concise
Scala’s syntax is lightweight var capital = Map( "US" → "Washington",
and concise.
"France" → "paris",
Contributors: "Japan" → "tokyo" )
– semicolon inference, capital += ( "Russia" → "Moskow" )
– type inference,
– lightweight classes, for ( (country, city) ← capital )
– extensible API’s, capital += ( country → city.capitalize )
– closures as
control abstractions. assert ( capital("Japan") == "Tokyo" )
Average reduction in LOC wrt Java: ≥ 2
due to concise syntax and better abstraction capabilities
***** Guy Steele:
Scala led to a 4 times LOC reduction in the Fortress typechecker *****
28
29. Scala is precise
Specify mapkind of collections: mutable
Specify implementation: HashMap
All code on the previous slide Specify map type: String to String
used library abstractions, not import scala.collection.mutable._
special syntax.
val capital =
new HashMap[String, String]
Advantage: Libraries are to
Mixin trait SynchronizedMap with SynchronizedMap[String, String] {
extensible and give fine-
make capital map thread-safe override def default(key: String) =
grained control. "?"
}
Elaborate static type system capital += ( "US" → "Washington",
catches many errors early. "France" → "Paris",
"Japan" → "Tokyo" )
Provide a default value: "?"
assert( capital("Russia") == "?" )
29
30. Big or small?
Every language design faces the
tension whether it should be big Scala adds Scala removes
or small:
– Big is good: expressive, + a pure object - static members
easy to use. system
– Small is good: elegant,
easy to learn. + operator - special treatment of
Can a language be both big and overloading primitive types
small? + closures as control - break, continue
abstractions
Scala’s approach: concentrate on
abstraction and composition + mixin composition - special treatment of
capabilities instead of basic with traits interfaces
language constructs. + abstract type - wildcards
members
+ pattern matching
30
31. Implicits are Poor Man’s Type Classes
/** A “type class” */
class Ord[T] { def < (x: T, y: T): Boolean }
/** An “instance definition” */
implicit object intOrd extends Ord[Int] {
def < (x: Int, y: Int) = x < y
}
/** Another instance definition */
implicit def listOrd[T](implicit tOrd: Ord[T]) = new Ord {
def < (xs: List[T], ys: List[T]) = (xs, ys) match {
case (_, Nil) => false
case (Nil, _) => true
case (x :: xs, y :: ts) => x < y || x == y && xs < ys
}
}
31
32. The Bottom Line
When going from Java to Scala, expect at least a factor of 2
reduction in LOC.
But does it matter?
Doesn’t Eclipse write these extra lines for me?
This does matter. Eye-tracking experiments* show that for program
comprehension, average time spent per word of source code is
constant.
So, roughly, half the code means half the time necessary to
understand it.
*G. Dubochet. Computer Code as a Medium for Human Communication: Are Programming
Languages Improving? In 21st Annual Psychology of Programming Interest Group Conference,
pages 174-187, Limerick, Ireland, 2009.
32
33. Extensibility
Take numeric data types:
– Today's languages support int,
long,
float,
double.
– Should they also support BigInt,
BigDecimal,
Complex,
Rational,
Interval,
Polynomial?
There are good reasons for each of these types
But a language combining them all would be too complex.
Better alternative: Let users grow their language according to their needs.
33
34. Scala is extensible
Guy Steele has formulated a
benchmark for measuring
language extensibility [Growing a
Language, OOPSLA 98]: scala> import Complex._
import Complex._
Can you add a type of
complex numbers to the scala> val x = 1 + 1 * i
library and make it work as if x: Complex = 1.0+1.0*i
it was a native number type?
scala> val y = x * i
Similar problems: Adding type y: Complex = -1.0+1.0*i
BigInt, Decimal, Intervals,
Polynomials... scala> val z = y + 1
z: Complex = 0.0+1.0*i
34
35. Implementing complex numbers
Objects replace static class members
object
Complex
{
val
i
=
new
Complex(0,
1)
Infix operations are method calls:
implicit
def
double2complex(x:
Double):
Complex
=
as a.+(b)
+ is an identifier; can be used as a a + b is the same
Class parameters instead of
method name
new
Complex(x,
0)
Implicit conversions for mixed arithmetic constructor
fields+ explicit
...
}
class
Complex(val
re:
Double,
val
im:
Double)
{
def
+(that:
Complex):
Complex
=
new
Complex(this.re
+
that.re,
this.im
+
that.im)
def
-‐(that:
Complex):
Complex
=
new
Complex(this.re
-‐
that.re,
this.im
-‐
that.im)
override
def
toString
=
re+(if
(im
<
0)
"-‐"+(-‐im)
else
"+"+im)+"*I"
...
}
35
36. Adding new datatypes - seamlessly
For instance type BigInt:
def
factorial(x:
BigInt):
BigInt
=
if
(x
==
0)
1
else
x
*
factorial(x
-‐
1)
Compare with using Java's class:
import
java.math.BigInteger
def
factorial(x:
BigInteger):
BigInteger
=
if
(x
==
BigInteger.ZERO)
BigInteger.ONE
else
x.multiply(factorial(x.subtract(BigInteger.ONE)))
}
36
37. Implementing new datatypes -
seamlessly
Infix operations are method calls:
Here's how BigInt is implemented a + b is the same as a.+(b)
+ is an identifier; can be used as a
method name
import
java.math.BigInteger
class
BigInt(val
bigInteger:
BigInteger)
extends
java.lang.Number
{
def
+
(that:
BigInt)
=
new
BigInt(this.bigInteger
add
that.bigInteger)
def
-‐
(that:
BigInt)
=
new
BigInt(this.bigInteger
subtract
that.bigInteger)
…
//
other
methods
implemented
analogously
}
37
38. Adding new control structures
• For instance using for resource control (in Java 7)
using
(new
BufferedReader(new
FileReader(path)))
{
f
=>
println(f.readLine())
}
• Instead of:
val
f
=
new
BufferedReader(new
FileReader(path))
try
{
println(f.readLine())
}
finally
{
if
(f
!=
null)
try
f.close()
catch
{
case
ex:
IOException
=>
}
}
38
39. Implementing new control structures:
Here's how one would go about implementing using:
is a type parameter... … supporting a method
def
using[T
<:
{
def
close()
}]
(resource:
T)
(block:
T
=>
Unit)
=
try
{
block(resource)
}
finally
{
A closure that takes a parameter
if
(resource
!=
null)
try
resource.close()
catch
{
case
ex:
IOException
=>
}
}
39
40. Producer or Consumer?
Scala feels radically different for producers and consumers
of advanced libraries.
For the consumer:
– Really easy
– Things work intuitively
– Can concentrate on domain, not implementation
For the producer:
– Sophisticated tool set
– Can push the boundaries of what’s possible
– Requires expertise and taste
40
42. Collection Properties
• object-oriented
scala> val ys = List(1, 2, 3)
• generic: List[T],
Map[K,
V]
ys: List[Int] = List(1, 2, 3)
• optionally persistent, e.g.
collection.immutable.Seq
scala> val xs: Seq[Int] = ys
xs: Seq[Int] = List(1, 2, 3)
• higher-order, with methods
such as foreach,
map,
scala> xs map (_ + 1)
filter.
res0: Seq[Int] = List(2, 3, 4)
• Uniform return type principle: scala> ys map (_ + 1)
Operations return collections of res1: List[Int] = List(2, 3, 4)
the same type (constructor) as
their left operand, as long as
this makes sense.
This makes a very elegant and powerful combination.
42
43. Using Collections: Map and filter
scala> val xs = List(1, 2, 3)
xs: List[Int] = List(1, 2, 3)
scala> val ys = xs map (x => x + 1)
ys: List[Int] = List(2, 3, 4)
scala> val ys = xs map (_ + 1)
ys: List[Int] = List(2, 3, 4)
scala> val zs = ys filter (_ % 2 == 0)
zs: List[Int] = List(2, 4)
scala> val as = ys map (0 to _)
as: List(Range(0, 1, 2), Range(0, 1, 2, 3), Range(0, 1, 2, 3, 4))
43
45. Using Collections: For Notation
scala> for (x <- xs) yield x + 1 // same as map
res14: List[Int] = List(2, 3, 4)
scala> for (x <- res14 if x % 2 == 0) yield x // ~ filter
res15: List[Int] = List(2, 4)
scala> for (x <- xs; y <- 0 to x) yield y // same as flatMap
res17: List[Int] = List(0, 1, 0, 1, 2, 0, 1, 2, 3)
45
47. An Example
• Task: Phone keys have mnemonics assigned to them.
val
mnemonics
=
Map(
'2'
-‐>
"ABC",
'3'
-‐>
"DEF",
'4'
-‐>
"GHI",
'5'
-‐>
"JKL",
'6'
-‐>
"MNO",
'7'
-‐>
"PQRS",
'8'
-‐>
"TUV",
'9'
-‐>
"WXYZ")
• Assume you are given a dictionary dict as a list of words. Design a class
Coder with a method translate such that
new
Coder(dict).translate(phoneNumber)
produces all phrases of words in dict that can serve as mnemonics for the
phone number.
• Example: The phone number “7225276257” should have the mnemonic
Scala
rocks
as one element of the list of solution phrases.
2-47
48. Program Example: Phone Mnemonics
• This example was taken from:
Lutz Prechelt: An Empirical Comparison of Seven Programming
Languages. IEEE Computer 33(10): 23-29 (2000)
• Tested with Tcl, Python, Perl, Rexx, Java, C++, C
• Code size medians:
– 100 loc for scripting languages
– 200-300 loc for the others
2-48
49. Outline of Class Coder
import
collection.mutable.HashMap
class
Coder(words:
List[String])
{
private
val
mnemonics
=
Map(
'2'
-‐>
"ABC",
'3'
-‐>
"DEF",
'4'
-‐>
"GHI",
'5'
-‐>
"JKL",
'6'
-‐>
"MNO",
'7'
-‐>
"PQRS",
'8'
-‐>
"TUV",
'9'
-‐>
"WXYZ")
/**
Invert
the
mnemonics
map
to
give
a
map
from
chars
'A'
...
'Z'
to
'2'
...
'9'
*/
private
val
upperCode:
Map[Char,
Char]
=
??
/**
Maps
a
word
to
the
digit
string
it
can
represent
*/
private
def
wordCode(word:
String):
String
=
??
/**
A
map
from
digit
strings
to
the
words
that
represent
them
*/
private
val
wordsForNum
=
new
HashMap[String,
Set[String]]
{
override
def
default(number:
String)
=
Set()
}
for
(word
<-‐
words)
wordsForNum(wordCode(word))
+=
word
/**
Return
all
ways
to
encode
a
number
as
a
list
of
words
*/
def
encode(number:
String):
List[List[String]]
=
??
/**
Maps
a
number
to
a
list
of
all
word
phrases
that
can
represent
it
*/
def
translate(number:
String):
List[String]
=
encode(number)
map
(_
mkString
"
")
}
2-49
50. Class Coder
(1)
import
collection.mutable.HashMap
class
Coder(words:
List[String])
{
private
val
mnemonics
=
Map(
'2'
-‐>
"ABC",
'3'
-‐>
"DEF",
'4'
-‐>
"GHI",
'5'
-‐>
"JKL",
'6'
-‐>
"MNO",
'7'
-‐>
"PQRS",
'8'
-‐>
"TUV",
'9'
-‐>
"WXYZ")
/**
Invert
the
mnemonics
map
to
give
a
map
from
chars
'A'
...
'Z'
to
'2'
...
'9'
*/
private
val
upperCode:
Map[Char,
Char]
=
for
((digit,
str)
<-‐
m;
letter
<-‐
str)
yield
(letter
-‐>
digit)
/**
Maps
a
word
to
the
digit
string
it
can
represent
*/
private
def
wordCode(word:
String):
String
=
word
map
(c
=>
upperCode(c.toUpper))
/**
A
map
from
digit
strings
to
the
words
that
represent
them
*/
private
val
wordsForNum
=
new
HashMap[String,
Set[String]]
{
override
def
default(number:
String)
=
Set()
}
for
(word
<-‐
words)
wordsForNum(wordCode(word))
+=
word
/**
Return
all
ways
to
encode
a
number
as
a
list
of
words
*/
def
encode(number:
String):
List[List[String]]
=
??
/**
Maps
a
number
to
a
list
of
all
word
phrases
that
can
represent
it
*/
def
translate(number:
String):
List[String]
=
encode(number)
map
(_
mkString
"
")
}
2-50
51. Class Coder
(2)
import
collection.mutable.HashMap
class
Coder(words:
List[String])
{
...
/**
Return
all
ways
to
encode
a
number
as
a
list
of
words
*/
def
encode(number:
String):
List[List[String]]
=
if
(number.isEmpty)
List(List())
else
for
{
splitPoint
<-‐
(1
to
number.length).toList
word
<-‐
wordsForNum(number
take
splitPoint)
rest
<-‐
encode(number
drop
splitPoint)
}
yield
word
::
rest
/**
Maps
a
number
to
a
list
of
all
word
phrases
that
can
represent
it
*/
def
translate(number:
String):
List[String]
=
encode(number)
map
(_
mkString
"
")
}
2-51
52. Going Further
• In Scala 2.9, collections will support parallel operations.
• Will be out by February 2011.
• The right tool for addressing the PPP (popular parallel programming)
challenge.
• I expect this to be the cornerstone for making use of multicores for
the rest of us.
52
54. Alex McGuire, EDF, who replaced majority of
300K lines Java with Scala:
“Picking up Scala was really easy.”Learning Curves
Productivitywriting Scala in Java style.”
“Begin by
“With Scala you can mix and match with your
old Java.”
200% can manage risk really well.”
“You
Scala
Alex Payne, Twitter:
“Ops doesn’t know it’s not Java”
100%
Keeps familiar environment: :
IDE’s: Eclipse, IDEA, Netbeans, ...
Tools: JavaRebel, FindBugs, Maven, ...
Libraries: nio, collections, FJ, ...
0% Frameworks; Spring, OSGI, J2EE, ...
4-6 weeks 8-12 weeks ...all work out of the box. .
54
55. How to get started
100s of resources on the
web.
Here are three great entry points:
• Scala for Java refugees
• Simply Scala
• Scalazine @ artima.com
55
56. How to find out more
Scala site: www.scala-lang.org 16 books
56
57. Support
Open Source Ecosystem ...
akka scalable actors
sbt simple build tool
lift, play web frameworks
kestrel, querulous middleware from Twitter
Migrations middleware from Sony
ScalaTest, specs, ScalaCheck testing support
ScalaModules OSGI integration
... complemented by commercial support
57
60. Scala cheat sheet (1): Definitions
Scala method definitions: Java method definition:
def
fun(x:
Int):
Int
=
{
int
fun(int
x)
{
result
return
result;
}
}
or
def
fun(x:
Int)
=
result
(no parameterless methods)
def
fun
=
result
Scala variable definitions: Java variable definitions:
var
x:
Int
=
expression
int
x
=
expression
val
x:
String
=
expression
final
String
x
=
expression
or
var
x
=
expression
val
x
=
expression
60
61. Scala cheat sheet (2): Expressions
Scala method calls: Java method call:
obj.meth(arg)
obj.meth(arg)
or obj
meth
arg
(no operator overloading)
Scala choice expressions: Java choice expressions, stats:
if
(cond)
expr1
else
expr2 cond
?
expr1
:
expr2
if
(cond)
return
expr1;
expr
match
{
else
return
expr2;
case
pat1
=>
expr1
....
switch
(expr)
{
case
patn
=>
exprn
case
pat1
:
return
expr1;
}
...
case
patn
:
return
exprn
;
}
//
statement
only
61
62. Scala cheat sheet (3): Objects and Classes
Scala Class and Object Java Class with static
class
Sample
{
class
Sample(x:
Int)
{
final
int
x;
def
instMeth(y:
Int)
=
x
+
y
Sample(int
x)
{
}
this.x
=
x
}
object
Sample
{
int
instMeth(int
y)
{
def
staticMeth(x:Int,
y:Int)
return
x
+
y;
=
x
*
y
}
}
static
int
staticMeth(int
x,int
y)
{
return
x
*
y;
}
}
62
63. Scala cheat sheet (4): Traits
Scala Trait Java Interface
trait
T
{
interface
T
{
def
absMeth(x:String):String
String
absMeth(String
x)
def
concreteMeth(x:
String)
=
(no concrete methods)
x+field
var
field
=
“!”
(no fields)
}
}
Scala mixin composition: Java extension + implementation:
class
C
extends
Super
class
C
extends
Super
with
T
implements
T
63