This document provides an introduction to the Scala programming language. It discusses that Scala is a hybrid language that is both object-oriented and functional, runs on the JVM, and provides seamless interoperability with Java. It highlights features of Scala such as pattern matching, traits, case classes, immutable data structures, lazy evaluation, and actors for concurrency.
8. “I can honestly say if someone had shown me the Programming Scala book by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy.“
James Strachan, creator of Groovy
9. “If I were to pick a language to use today other than Java, it would be Scala.”
James Gosling
19. object MyApp {
def main(args: Array[String]) {
val user = args(0)
println(“Hello, ”+user+“!”)
}
}
Local type inference
less… “typing”
20. class StringArrayFactory {
def create: Array[String] = {
val array: Array[String] =
Array[String](“1”, “2”, “3”)
array
}
}
Local type inference
less… “typing”
21. class StringArrayFactory {
def create = {
val array = Array(“1”, “2”, “3”)
array
}
}
Local type inference
less… “typing”
22. // Scala
class Person(
var name: String,
var age: Int
)
Declaring classes
…concisely
// Java
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
41. val doub: Int => Int = (x: Int) => x * 2
doub(1)
2
First class functions
functions are objects too
42. val doub = (x: Int) => x * 2
List(1, 2, 3).map(doub)
List(2, 4, 6)
First class functions
as higher order parameters
43. List[Int](1, 2, 3).map((x: Int) => x * 2)
// more type inference
List(1, 2, 3).map(x => x * 2)
// or even shorter
List(1, 2, 3).map(_ * 2)
Functions with sugar
make code sweeter
44. var step = 1
val inc = x => x + step
inc(5)
6
step = 2
inc(5)
7
Closures
functions that “capture” their environment
45. // Java
button.addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e) {
System.out.println(e);
}
}
// Scala
listenTo(button)
reactions += { case e => println(e) }
First class functions
because you write them in Java all the time
47. Pattern matching
…is concise
// Scala
reactions += {
case m: MouseEntered =>
println(“I see it!”)
case m: MouseExited =>
println(“Lost it.”)
case m: MouseClicked =>
println(“Poked!”)
}
// Java
button.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
System.out.println(“I see it!”);
}
public void mouseExited(MouseEvent e) {
System.out.println(“Lost it.”);
}
public void mouseClicked(MouseEvent e) {
System.out.println(“Poked!”);
}
}
// ...alternative - isinstanceof
48. trait Tree
case class Node(l: Tree, r: Tree)
extends Tree
case object Leaf
extends Tree
Pattern matching
…is precise
49. def b(t: Tree): Int = t match {
case Node(Leaf, Node(_, _)) |
Node(Node(_, _), Leaf) => -1
case Node(l, r) =>
val (ld, rd) = (b(l), b(r))
if (ld == rd) ld + 1 else -1
case Leaf => 0
case _ => error(“Unknown tree!”)
}
Pattern matching
…is precise
50. sealed trait Tree
...
def b(t: Tree): Int = t match {
case Node(Leaf, Node(_, _)) |
Node(Node(_, _), Leaf) => -1
case Node(l, r) =>
val (ld, rd) = (b(l), b(r))
if (ld == rd) ld + 1 else -1
case Leaf => 0
}
Pattern matching
…is exhaustive
51. def matchingMeSoftly(a: Any): Any =
a match {
case 11 => “eleven”
case s: String => “’%s’”.format(s)
case <tag>{t}</tag> => t
case Array(1, 2, 3) => “1, 2, 3”
case head :: tail => tail
case _ => null
}
Pattern matching
…is extensible
53. lazy values
don’t compute if there’s no demand
class User(id: Int) {
lazy val followernum =
from(followers)(f =>
where(id === f.fid)
compute(countDistinct(f.fid))
)
}
54. Call by name
evaluate only when you have to
def withErrorOut(body: =>Unit) = {
val old = Console.out
Console.setOut(Console.err)
try body
finally Console.setOut(old)
}
...
withErrorOut {
if (n < 0) println(“n too small”)
}
61. for comprehensions
traverse anything
for (x <- List(1, 2, 3)) println(x)
List(1, 2, 3).foreach(x => println(x))
for (x <- 0 until 10) println(x)
(0 until 10).foreach(x => println(x))
Range(0, 10, 1).foreach(x => println(x))
62. for comprehensions
map anything
for (x <- List(1, 2, 3)) yield x * 2
List(1, 2, 3).map(x => x * 2)
for (x <- List(1, 2); y <- List(1, 2))
yield x * y
List(1, 2).flatMap(x =>
List(1, 2).map(y => x * y)
)
List(1, 2, 2, 4)
63. for comprehensions
like SQL queries
for {
p <- people
if p.age > 25
s <- schools
if p.degree == s.degree
} yield (p, s)
// pairs of people older than 25 and
// schools they possibly attended
64. Collections
easy to create
val phonebook = Map(
“Jean” -> “123456”,
“Damien” -> “666666”)
val meetings = ArrayBuffer(
“Dante”, “Damien”, “Sophie”)
println(phonebook(meetings(1)))
65. Collections
high-level combinators
// Java
boolean isOk = true
for (int i = 0; i < name.length(); i++) {
if (isLetterOrDigit(name.charAt(i)) {
isOk = false;
break;
}
}
68. Collections
high-level combinators
// count the total number of different
// surnames shared by at least 2 adults
people.filter(_.age >= 18)
69. Collections
high-level combinators
// count the total number of different
// surnames shared by at least 2 adults
people.filter(_.age >= 18)
.groupBy(_.surname): Map[String, List[Person]]
70. Collections
high-level combinators
// count the total number of different
// surnames shared by at least 2 adults
people.filter(_.age >= 18)
.groupBy(_.surname): Map[String, List[Person]]
.count { case (s, l) => l.size >= 2 }
71. Lists
an immutable sequence
val countdown = List(3, 2, 1)
3
2
1
countdown
72. Lists
an immutable sequence
val countdown = List(3, 2, 1)
val longer = 4 :: countdown
3
2
1
4
countdown
longer
73. Lists
an immutable sequence
val countdown = List(3, 2, 1)
val longer = 4 :: countdown
val fast = 10 :: countdown
3
2
1
4
10
countdown
longer
fast
74. Lists
an immutable sequence
val countdown = List(3, 2, 1)
val longer = 4 :: countdown
val fast = 10 :: countdown
val withzero = countdown ::: List(0)
3
2
1
4
10
3
2
1
0
countdown
longer
fast
withzero
75. Buffers
mutable sequences
val b = ArrayBuffer(1, 2, 3)
b += 4
b += 5
b += 6
ArrayBuffer(1, 2, 3, 4, 5, 6)
76. Maps
mutable or immutable, sorted or unsorted
import collection._
val m = mutable.Map(“Heidfeld” -> 1,
“Schumacher” -> 2)
m += “Hakkinen” -> 3
val im = immutable.Map(“Schumacher” -> 1)
77. Hash tries
persistence through efficient structural sharing
val im0: Map[Int, Int] = ...
im0
78. Hash tries
persistence through efficient structural sharing
val im0: Map[Int, Int] = ...
val im1 = im0 + (1 -> 1)
im0
im1
79. Hash tries
persistence through efficient structural sharing
val im0: Map[Int, Int] = ...
val im1 = im0 + (1 -> 1)
val im2 = im1 + (2 -> 2)
im0
im1
im2
80. Hash tries
persistence through efficient structural sharing
val im0: Map[Int, Int] = ...
val im1 = im0 + (1 -> 1)
val im2 = im1 + (2 -> 2)
val im3 = im2 + (3 -> 6)
im0
im1
im2
im3
85. actors
road to safer concurrency
val a = actor {
react {
case i: Int => println(i)
}
}
...
a ! 5
86. Custom control flow
it’s all about control
def myWhile(c: =>Boolean)(b: =>Unit) {
if (c) {
b
myWhile(c)(b)
}
}
87. Custom control flow
it’s all about control
@tailrec
def myWhile(c: =>Boolean)(b: =>Unit) {
if (c) {
b
myWhile(c)(b)
}
}
88. Custom control flow
it’s all about control
@tailrec
def myWhile(c: =>Boolean)(b: =>Unit) {
if (c) {
b
myWhile(c)(b)
}
}
var i = 0
myWhile (i < 5) {
i += 1
}
89. ARM
automatic resource management
withFile (“~/.bashrc”) { f =>
for (l <- f.lines) {
if (“#”.r.findFirstIn(l) != None)
println(l)
}
}
90. ScalaTest
behavioral testing framework
“A list” should {
“be a double reverse of itself” in {
val ls = List(1, 2, 3, 4, 5, 6)
ls.reverse.reverse should equal (ls)
}
}
91. BaySick
Basic DSL in Scala
10 PRINT “Baysick Lunar Lander v0.9”
20 LET ('dist := 100)
30 LET ('v := 1)
40 LET ('fuel := 1000)
50 LET ('mass := 1000)
...
95. implicit conversions
pimping your libraries since 2006
import scalaj.collection._
val list = new java.util.ArrayList[Int]
list.add(1)
list.add(2)
list.add(3)
...
for (x <- list) yield x * 2
96. implicit conversions
pimping your libraries since 2006
import scalaj.collection._
val list = new java.util.ArrayList[Int]
list.add(1)
list.add(2)
list.add(3)
...
for (x <- list) yield x * 2
// list.map(x => x * 2)
97. implicit conversions
pimping your libraries since 2006
import scalaj.collection._
val list = new java.util.ArrayList[Int]
list.add(1)
list.add(2)
list.add(3)
...
for (x <- list) yield x * 2
// jlist2slist(list).map(x => x * 2)
98. implicit arguments
restricting operations on types
val is = SortedSet(1, 2, 3)
case class Man(id: Int)
...
implicit object MenOrd extends Ordering[Man] {
def compare(x: Man, y: Man) = x.id – y.id
}
val ms = SortedSet(Person(1), Person(2))