2. If I were to pick a language to use on the JVM
today other than Java, it would be Scala.
– James Gosling, creator of Java
http://www.adam-bien.com/roller/abien/entry/java_net_javaone_which_programming
Scala, it must be stated, is the current heir apparent to the
Java throne. No other language on the JVM seems as
capable of being a "replacement for Java" as Scala, and
the momentum behind Scala is now unquestionable.
– Charlies Nutter, JRuby lead
http://blog.headius.com/2009/04/future-part-one.html
My tip though for the long term replacement of javac is Scala.
I'm very impressed with it! I can honestly say if someone had
shown me the Programming in Scala book […] back in 2003
I'd probably have never created Groovy.
– James Strachan, creator of Groovy
http://macstrac.blogspot.com/2009/04/scala-as-long-term-replacement-for.html
3. Agenda
● Cosa è, e perché Scala?
● Introduzione a Scala
– Sintassi di base
– Pattern matching
– Funzioni!
– Classi, traits e mixins
● Qualche “chicca”
● NON in queste slides (una prossima volta?):
– Continuations
– For-comprehensions and Monads
– Parallelismo e Actors
4. Scala
● Porgrammazione object oriented E funzionale
● Tipizzazione statica
● Compatibile (interoperabile) con Java
– Compilazione in bytecode Java
– Conversioni automatiche (collection, tipi base)
● Mixed compilation!
– … e con .NET!
● “Un java migliore”?
5. public class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
class Person(var age: Int, var name: String)
6. List<Person> persons = ...
List<Person> adults = new LinkedList<Person>();
List<Person> kids = new LinkedList<Person>();
for (Person person : persons) {
if (person.getAge() < 18) {
kids.add(person);
} else {
adults.add(person);
}
}
val persons: List[Person] = ...
val (kids, adults) = persons.partition(_.age < 18)
12. “Valori” (~costanti)
class DbImport(private val config: Config,
private val connection:
() => java.sql.Connection,
...) {
val db = Database(config,
useSessionFactory = false,
useConnectionPool = false)
...
Readonly/const (ma non propagato)
22. Collections
val list = List("apple", "orange", "banana")
val map = Map(1 -> "uno", 2 -> "due")
val array = Array(1, 2, 3, 4, 5)
list(1) // orange
map(2) // due
array(3) // 4
23. myObject match {
case 1 => println("Primo")
case 2 => println("Secondo")
case _ => println("Orru...")
}
Pattern matching
24. myObject match {
case i: Int => println("Un numero " + I * 2)
case s: String => println("Del testo " + s.toUpper)
case _ => println("Orru...")
}
Pattern matching
25. val email = """(.+)@(.+)""".r
"scala@java.no" match {
case email(name, domain) =>
println("User " + name + " at " + domain)
case x => println(x + " is not an email")
}
Pattern matching
26. val numbers = List(1, 2, 3)
val secondNumber = numbers match {
case List(_, i, _*) => Some(i)
case _ => None
}
=> secondNumber: Option[Int] = Some(2)
Pattern matching
27. Funzioni
Predicate<Integer> even = new Predicate<Integer>() {
@Override
public boolean apply(Integer i) {
return i % 2 == 0;
}
};
List<Integer> numbers = … // 1, 2, 3, 4
Iterable<Integer> evenNums =
Iterables.filter(numbers, even);
=> [2, 4]
Google collections:
28. Funzioni
val even = (i: Int) => i % 2 == 0
val numbers = List(1, 2, 3, 4)
val evenNums = numbers.filter(even)
=> List(2, 4)
Scala collections:
29. Funzioni
val numbers = List(1, 2, 3, 4)
val evenNums = numbers.filter((i: Int) => i % 2 == 0)
=> List(2, 4)
Scala collections:
30. Funzioni
val numbers = List(1, 2, 3, 4)
val evenNums = numbers.filter(i => i % 2 == 0)
=> List(2, 4)
Scala collections:
31. Funzioni
val numbers = List(1, 2, 3, 4)
val evenNums = numbers.filter(_ % 2 == 0)
=> List(2, 4)
Scala collections:
32. Funzioni
Predicate<Integer> even = new Predicate<Integer>() {
@Override
public boolean apply(Integer i) {
return i % 2 == 0;
}
};
val evenNums = numbers.filter(_ % 2 == 0)
35. Funzioni: cittadini di prima classe
val even = Function[Int, Boolean] {
def apply(i: Int) = i % 2 == 0
}
val even: (Int => Boolean) = (i: Int) => i % 2 == 0
val even = (i: Int) => i % 2 == 0
even.apply(42) // true
even(13) // false
36. Funzioni e collections
numbers.filter(i => i > 2) // List(3, 4, 5)
numbers.find(i => i > 2) // Some(3)
numbers.exists(i => i > 2) // true
numbers.forall(i => i > 2) // false
numbers.map(i => i * 2) // List(2, 4, 6, 8, 10)
numbers.foldLeft(0) { (a, b) => a + b } // 15
38. Closures
val people = List(Person(“Alice”), Person(“Orru”))
val name = “Orru”
val nameFilter = (p: Person) => p.name == name
people.filter(nameFilter) // Person(“Orru”)
39. Closures
val people = List(Person(“Alice”), Person(“Orru”))
var name = “Orru”
val nameFilter = (p: Person) => p.name == name
people.filter(nameFilter) // Person(“Orru”)
name = “Alice”
people.filter(nameFilter) // Person(“Alice”)
40. Funzioni di ordine superiore
● Funzioni che prendono funzioni come
parametri e/o ritornarno funzioni
def test(numbers: List[Int], f: Int => Boolean) =
numbers.map(tall => f(tall))
// List[Boolean]
41. call-by-value vs. “call-by-name”
● by-value: espressioni valutate prima della
chiamata
● by-name: espressioni valutate all'interno del
chiamante
– Quando la valutazione e' costosa, non sempre
necessaria; per avere computazioni “on-demand”
computing
– Simile a “lazy” (che, tra parentesi, pure c'e' in
Scala)
– APIs performanti, e intuitive particolarmente per le
collection
42. call-by-value vs. call-by-name
Example: Logging
def thisTakesTime(): String = {
// leeento! Prende la stringa dal DB magari!
}
def debug(s: String) {
println(“debug”)
if (logLevel <= DEBUG) println(s)
}
logger.debug(thisTakesTime())
44. Gli “statement” hanno un valore
val numbers = for (i <- 1 to 10) yield i
val res = if (cond) x else y
val res2 = try { x } catch { … y } finally { … }
(Almost) everything is an expression
45. Classi e costruttori
Scala:
class Person(val name: String)
Java:
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
46. Classi e costruttori
class Person(val age: Int) {
def this() = this(42)
var name: String = _
override def toString = "Ciao, sono " + name
}
48. Generici
// Structural Typing (avoids us doing manual reflection)
type Precompiler = {
var sources: Array[File]
...
var info: {def apply(v1:String):Unit}
...
def execute(): Unit
}
val precompilerClassName = "org.fusesource.scalate.support.Precompiler"
val precompiler = loader.loadClass(precompilerClassName).
newInstance.
asInstanceOf[Precompiler]
precompiler.info = (value:String) => getLog.info(value)
precompiler.sources = Array(mojo.warSourceDirectory,
mojo.resourcesSourceDirectory)
...
precompiler.execute
49. Traits (= Interface + Mixin)
● “Eredita' multipla fatta bene”
● Si possono avere implementazioni di metodi
(Java8? C# 5?)
● Si possono implementare metodi
● Si possono avere metodi e campi astratti
● Niente costruttori (astratte)
● E' possibile chiamare la classe base
– Ma con controlli!
53. “Dynamic mixins”
class Person(val name: String, val age: Int) {
override def toString = "My name is " + name
}
trait Loud {
override def toString = super.toString.toUpperCase
}
val person = new Person("Orru", 18) with Loud
println(person)
=> MY NAME IS ORRU
55. def using[T <: { def close() }, A]
(closeable: T)
(f: T => A) = {
try {
f(closeable)
} finally {
if (closeable != null) {
try {
closeable.close()
}
catch {
case e: Exception => // Do something clever!?
}
}
}
}
56. For-loops
Scala:
for (i <- 0 to 3) {
...
}
for (s <- args) println(s)
// args.foreach(println(_))
Java:
for (int i = 0; i < 4; i++) {
...
}
for (String s : args) {
System.out.println(s);
}
57. E ci sono molte altre cose...
● Tuples
● Singleton objects
● For-comprehensions
● Implicit conversions
● Actors
● XML come tipo nativo
● Parsers
● Continuations
58. Tuples
Scala:
val tuple: Tuple2[Int, String] =
(1, “apple”)
val quadruple =
(2, “orange”, 0.5d, false)
Java:
Pair<Integer, String> tuple = new
Pair<Integer, String>(1, “apple”)
... yeah right... ;-)
59. ScalaTest demo
val travels = travelFinder.buildTravels(trips)
travels should have size 2
val trips = travels.flatMap(_._2)
val bikeTrips = trips.filter(_.bikes.getOrElse(0) > 0)
bikeTrips should not be ('empty)
otherTrips.size should be (2)
otherTrips.map(_.id) should contain leg1.id
otherTrips.map(_.id) should contain leg2.id
travels.filter(_.travelType == TravelType.Bike)
should not be ('empty)
val bikeDistance = travels.flatMap(_._1.details).
filter(_.travelType == TravelType.Bike).
map(_.fareKm.getOrElse(0.0)).sum
bikeDistance should be > 0.0
60. Imparare scala
● Sintassi... dipende!
– E' facile scrivere Java-ish Scala
● Il linguaggio cresce man mano che lo capiete
● Vi lascia migrare gradualmente a uno stile piu'
funzionale
● Vi lascia mantenere “strtuttura”!
● Ha delle “chicche”
– prese singolarmente, niente di che
– Insieme...
61. Programmazione funzionale “pura”
● Funzioni “matematiche”
– Niente side effects
● In pratica: solo oggetti immutabili
– Tutti i campi sono immutabili (val)
– Le chiamate ai metodi non hanno side-effects
● Eh?
● Hint: producono un nuovo oggetto
– => tutti i metodi ritornano qualcosa, un valore!
62. Esempio: scala.List
● head :: tail
val list = List(1, 2)
val myList = 1 :: 2 :: Nil
// 0 :: 1 :: 2 :: Nil
val myotherList = 0 :: myList
63. Cercare di essere “puri”
● Concorrenza
– Iterator.par.
● Facile evitare errori
– NullPointerException
● Facile da testare
● scala.collection.immutable
– ...oppure scala.collection.mutable!