Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Scala
Lorenzo Dematté
Trenta3dev
Materiale basato su esempi di
Alf Kristian Støyle, Micheal Stal, ed altri
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
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
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”?
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)
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)
using(new BufferedReader(new FileReader("f.txt"))) {
reader => println(reader.readLine())
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("f.txt"));
System.out.println(reader.readLine());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// Exception on close, ignore
}
}
}
Tipi
Scala
s: String
i: Int
Java
String s
int i / Integer i
Variabili
var i: Int = 42
Variabili
var i = 42 // type inference
i = 3
i = "Hello world!" // tipizzazione statica
“Valori” (~costanti)
val i = 42
i = 3 // errore di compilazione
“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)
Metodi
def sum(a: Int, b: Int): Int = {
return a + b
}
Metodi
def sum(a: Int, b: Int): Int = {
a + b
}
Metodi
def sum(a: Int, b: Int) = {
a + b
}
Metodi
def sum(a: Int, b: Int) = a + b
Metodi
public String hello;
public String getHello(){ … }
public void setHello(String s) { … }
Metodi
public String hello;
public String getHello(){ … }
public void setHello(String s) { … }
val hello = “hello” // val s = obj.hello
def hello = {
println("Hello, " + name)
return “hello”
} // val s = obj.hello
Metodi
Scala:
myObject.myMethod(1)
myObject myMethod(1)
myObject myMethod 1
myObject.myOtherMethod(1, 2)
myObject myOtherMethod(1, 2)
myObject.myMutatingMethod()
myObject.myMutatingMethod
myObject myMutatingMethod
Java:
myObject.myMethod(1);
myObject.myOtherMethod(1, 2);
myObject.myMutatingMethod()
Metodi
"apple".charAt(0)
"apple" charAt 0
1.0.+(2.0)
1.0 + 2.0
Metodi
"apple".charAt(0)
"apple" charAt 0
1.0.+(2.0)
1.0 + 2.0
trait NumericalExpression[A] extends TypedExpressionNode[A] {
def ===[B](b: NumericalExpression[B]) =
new EqualityExpression(this, b)
...
def > [B](b: NumericalExpression[B]) = gt(b)
...
def +[B](b: NumericalExpression[B]) = plus(b)
...
def gt [B](b: NumericalExpression[B]) =
new BinaryOperatorNodeLogicalBoolean(this, b, ">")
...
table.deleteWhere(ob => ob.tr_id === t.id and ob.data gt data)
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
myObject match {
case 1 => println("Primo")
case 2 => println("Secondo")
case _ => println("Orru...")
}
Pattern matching
myObject match {
case i: Int => println("Un numero " + I * 2)
case s: String => println("Del testo " + s.toUpper)
case _ => println("Orru...")
}
Pattern matching
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
val numbers = List(1, 2, 3)
val secondNumber = numbers match {
case List(_, i, _*) => Some(i)
case _ => None
}
=> secondNumber: Option[Int] = Some(2)
Pattern matching
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:
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:
Funzioni
val numbers = List(1, 2, 3, 4)
val evenNums = numbers.filter((i: Int) => i % 2 == 0)
=> List(2, 4)
Scala collections:
Funzioni
val numbers = List(1, 2, 3, 4)
val evenNums = numbers.filter(i => i % 2 == 0)
=> List(2, 4)
Scala collections:
Funzioni
val numbers = List(1, 2, 3, 4)
val evenNums = numbers.filter(_ % 2 == 0)
=> List(2, 4)
Scala collections:
Funzioni
Predicate<Integer> even = new Predicate<Integer>() {
@Override
public boolean apply(Integer i) {
return i % 2 == 0;
}
};
val evenNums = numbers.filter(_ % 2 == 0)
Funzioni
Predicate<Integer> even = i -> i % 2 == 0
Java8 lambda expressions:
val even = (i: Int) => i % 2 == 0
Scala functions:
Funzioni
Iterables.filter(numbers, i -> i % 2 == 0)
Java8 lambda expressions:
numbers.filter(_ % 2 == 0)
Scala functions:
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
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
“Interfacce funzioniali” e lambda
helloButton.addActionListener(e =>
println(“Hello World!”))
Closures
val people = List(Person(“Alice”), Person(“Orru”))
val name = “Orru”
val nameFilter = (p: Person) => p.name == name
people.filter(nameFilter) // Person(“Orru”)
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”)
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]
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
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())
“call-by-name”
def debug(s: => String) {
println(“debug”)
if (logLevel <= DEBUG)
println(s)
}
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
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;
}
}
Classi e costruttori
class Person(val age: Int) {
def this() = this(42)
var name: String = _
override def toString = "Ciao, sono " + name
}
Generici
Scala:
List[String]
Java:
List<String>
● Equivalenza strutturale!
– Tipizzazione “dinamica” con la rete di sicurezza
– Reflection? Facile!
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
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!
scala.Ordered trait
trait Ordered[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
}
Ordered trait
class Person(val age: Int) extends Ordered[Person] {
def compare(other: Person) = this.age - other.age
}
val person1 = new Person(21)
val person2 = new Person(31)
person1 < person2 // true
person1 <= person2 // true
person1 >= person2 // false
Generici
● Ricordate l'equivalenza strutturale?
“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
using(new BufferedReader(new FileReader("f.txt"))) {
reader => println(reader.readLine())
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("f.txt"));
System.out.println(reader.readLine());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// Exception on close, ignore
}
}
}
Ricordate?
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!?
}
}
}
}
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);
}
E ci sono molte altre cose...
● Tuples
● Singleton objects
● For-comprehensions
● Implicit conversions
● Actors
● XML come tipo nativo
● Parsers
● Continuations
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... ;-)
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
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...
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!
Esempio: scala.List
● head :: tail
val list = List(1, 2)
val myList = 1 :: 2 :: Nil
// 0 :: 1 :: 2 :: Nil
val myotherList = 0 :: myList
Cercare di essere “puri”
● Concorrenza
– Iterator.par.
● Facile evitare errori
– NullPointerException
● Facile da testare
● scala.collection.immutable
– ...oppure scala.collection.mutable!

More Related Content

Introduction to Scala

  • 1. Scala Lorenzo Dematté Trenta3dev Materiale basato su esempi di Alf Kristian Støyle, Micheal Stal, ed altri
  • 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)
  • 7. using(new BufferedReader(new FileReader("f.txt"))) { reader => println(reader.readLine()) } BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("f.txt")); System.out.println(reader.readLine()); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { // Exception on close, ignore } } }
  • 10. Variabili var i = 42 // type inference i = 3 i = "Hello world!" // tipizzazione statica
  • 11. “Valori” (~costanti) val i = 42 i = 3 // errore di compilazione
  • 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)
  • 13. Metodi def sum(a: Int, b: Int): Int = { return a + b }
  • 14. Metodi def sum(a: Int, b: Int): Int = { a + b }
  • 15. Metodi def sum(a: Int, b: Int) = { a + b }
  • 16. Metodi def sum(a: Int, b: Int) = a + b
  • 17. Metodi public String hello; public String getHello(){ … } public void setHello(String s) { … }
  • 18. Metodi public String hello; public String getHello(){ … } public void setHello(String s) { … } val hello = “hello” // val s = obj.hello def hello = { println("Hello, " + name) return “hello” } // val s = obj.hello
  • 19. Metodi Scala: myObject.myMethod(1) myObject myMethod(1) myObject myMethod 1 myObject.myOtherMethod(1, 2) myObject myOtherMethod(1, 2) myObject.myMutatingMethod() myObject.myMutatingMethod myObject myMutatingMethod Java: myObject.myMethod(1); myObject.myOtherMethod(1, 2); myObject.myMutatingMethod()
  • 21. Metodi "apple".charAt(0) "apple" charAt 0 1.0.+(2.0) 1.0 + 2.0 trait NumericalExpression[A] extends TypedExpressionNode[A] { def ===[B](b: NumericalExpression[B]) = new EqualityExpression(this, b) ... def > [B](b: NumericalExpression[B]) = gt(b) ... def +[B](b: NumericalExpression[B]) = plus(b) ... def gt [B](b: NumericalExpression[B]) = new BinaryOperatorNodeLogicalBoolean(this, b, ">") ... table.deleteWhere(ob => ob.tr_id === t.id and ob.data gt data)
  • 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)
  • 33. Funzioni Predicate<Integer> even = i -> i % 2 == 0 Java8 lambda expressions: val even = (i: Int) => i % 2 == 0 Scala functions:
  • 34. Funzioni Iterables.filter(numbers, i -> i % 2 == 0) Java8 lambda expressions: numbers.filter(_ % 2 == 0) Scala functions:
  • 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
  • 37. “Interfacce funzioniali” e lambda helloButton.addActionListener(e => println(“Hello World!”))
  • 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())
  • 43. “call-by-name” def debug(s: => String) { println(“debug”) if (logLevel <= DEBUG) println(s) }
  • 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 }
  • 47. Generici Scala: List[String] Java: List<String> ● Equivalenza strutturale! – Tipizzazione “dinamica” con la rete di sicurezza – Reflection? Facile!
  • 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!
  • 50. scala.Ordered trait trait Ordered[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 }
  • 51. Ordered trait class Person(val age: Int) extends Ordered[Person] { def compare(other: Person) = this.age - other.age } val person1 = new Person(21) val person2 = new Person(31) person1 < person2 // true person1 <= person2 // true person1 >= person2 // false
  • 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
  • 54. using(new BufferedReader(new FileReader("f.txt"))) { reader => println(reader.readLine()) } BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("f.txt")); System.out.println(reader.readLine()); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { // Exception on close, ignore } } } Ricordate?
  • 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!