1. S CALA: ein kurzer Überblick
JUGHRO-Treffen November 2011
Roland Ewald
Institut für Informatik, Universität Rostock
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 1
2. Disclaimer
• Ich bin ein S CALA-Anfänger
• Übergang schrittweise &
punktuell
• No Silver Bullet
Image source: user whatnot, http://www.flickr.com/photos/whatnot/6853556/
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 2
3. Überblick
Warum Scala?
Snippets & Grundkonzepte
Beispiel: Rationale Zahlen
Praxis
Zusammenfassung
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 3
4. Warum
• Interessante Sprache :-)
• Nutzt Java als Plattform (JVM)
• ’Kritische Masse’ scheint erreicht (scala-Tag #130 bei stackoverflow; noch
vor math, testing, java-ee oder tomcat)
• Ist nicht mehr ’bleeding edge’ (aktuell Version 2.9, entwickelt seit 2003)
• Mehr Gründe auf http://www.scala-lang.org
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 4
5. Motivation
• Scala = Scalable Language
• Soll mit Nutzeranforderungen wachsen
• Skript ⇐⇒ Große Anwendung
• Statisch getypt (wie Java)
• Unterstützt objektorientierte UND funktionale Programmierung
• Weniger Boilerplate (kann Codelänge um 50% – 90% reduzieren)
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 5
6. Material
• Gutes Buch vom Entwickler der Sprache
(Martin Odersky)
• Erste Auflage frei verfügbar:
http://www.artima.com/pins1ed/
• Blog-Serie Scala for Java Refugees:
http://www.codecommit.com/blog/scala/
roundup-scala-for-java-refugees
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 6
7. Funktionale Programmierung1
1. Funktionen sind Objekte erster Klasse
2. Funktionen haben keine Seiteneffekte
val meineFunktion = (x:Int, y:Int) => x + y
println(meineFunktion(1,1))
(Ein Welt für sich, Grundidee bereits durch λ-Kalkül von Church entwickelt.
Beliebte funktionale Sprachen: Scheme, Haskell, OCaml, F#)
1 Aus Sicht der Scala-Entwickler :)
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 7
8. Maps, Operatoren & das Factory-Pattern
var capital = Map("US" -> "Washington", "France" -> "Paris")
capital += ("Japan" -> "Tokyo")
println(capital("France"))
Codebeispiel aus Odersky et al., Programming in Scala, 2008
Warum leicht lesbar?
• Typinferenz
• Factory-Methode ’versteckt’
• Sinvolle Operatoren
• Vordefinierte Funktionen
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 8
9. Interoperabilität mit Java / Neue Typen erzeugen
{
import java.math.BigInteger
def factorial(x: BigInteger): BigInteger =
if (x == BigInteger.ZERO)
BigInteger.ONE
else
x.multiply(factorial(x.subtract(BigInteger.ONE)))
println(factorial(BigInteger.TEN))
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
def factorial(x: BigInt): BigInt =
if (x == 0) 1 else x * factorial(x - 1)
println(factorial(10))
Codebeispiel aus Odersky et al., Programming in Scala, 2008
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 9
10. Neue Kontrollstrukturen erzeugen2
actor {
var sum = 0
loop {
receive {
case Data(bytes) => sum += hash(bytes)
case GetSum(requester) => requester ! sum
}
}
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
2 Diese hier sind von Erlang geborgt :-)
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 10
11. Weniger Boilerplate (durch ’Properties’)
class MyClass {
private int index;
private String name;
public MyClass(int index, String name) {
this.index = index;
this.name = name;
}
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
class MyClass(index: Int, name: String)
Codebeispiel aus Odersky et al., Programming in Scala, 2008
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 11
12. Weniger Boilerplate (durch funktionale
Programmierung)
boolean nameHasUpperCase = false;
for (int i = 0; i < name.length(); ++i) {
if (Character.isUpperCase(name.charAt(i))) {
nameHasUpperCase = true;
break;
}
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
val nameHasUpperCase
= name.exists(_.isUpperCase)
Codebeispiel aus Odersky et al., Programming in Scala, 2008
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 12
13. Weniger Boilerplate (durch Support für n-Tupel)3
//In James II wäre das:
import james.core.util.misc.Pair;
//...
Pair<Integer,String> pair = new
Pair<Integer,String>(99,"Luftballons");
System.out.println(pair.getFirstValue());
System.out.println(pair.getSecondValue());
var pair = (99, "Luftballons")
println(pair._1)
println(pair._2)
Codebeispiel aus Odersky et al., Programming in Scala, 2008
3 ∀n ≤ 22
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 13
14. Grundideen
Funktionen...
• geben immer etwas zurück (zumindest Unit)
• können teilweise definiert werden (⇒ Currying/Closures)
• werden genauso behandelt wie Werte (⇒Werte sind konstante Funktionen)4
• können lokale Funktionen enthalten
• können echt seltsame Namen haben, z.B. +, +=, ::, /
• können unterschiedlich aufgerufen werden
4 Konvention: myObject.x hat keine Seiteneffekte, myObject.x() schon
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 14
15. Aufruf von Funktionen
class MeineKlasse {
def verdoppeln(x: Int) = 2 * x
def <<(x: Int) = verdoppeln(x)
}
val meinObjekt = new MeineKlasse()
println(meinObjekt.verdoppeln(2))
println(meinObjekt.<<(2))
println(meinObjekt verdoppeln 2)
println(meinObjekt << 2)
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 15
16. Aufruf von Funktionen
def main(args: Array[String]) {
args.foreach((arg: String) => println(arg))
args.foreach(arg => println(arg))
args.foreach(println(_))
args.foreach(println)
}
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 16
17. Grundideen
• Mehrere public Klassen pro Datei erlaubt.
• Keine primitiven Datentypen mehr (1.toString ist OK)
• Imports haben einen Gültigkeitsbereich
• Sichtbarkeit kann sehr feingranular eingestellt werden
(z.B. protected[my.package], private[this])
• Objects sind Singletons
(und enthalten alle statischen Methoden, static gibt es also nicht)
• Implizite Typumwandlungen
• case classes für Pattern Matching
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 17
18. Was ist (fast) gleich?
• Grundlegende Organisation des Codes (Pakete + Klassen)
• Kontrollstrukturen wie for, while, if etc.
(teilw. mächtiger, z.B. switch ⇒ match)
• Klassenbibliothek (Collections etc.)
• Speicherverwaltung (new wird jedoch weniger benutzt, wegen Companion
Objects und FP)
• Fehlerbehandlung (Exceptions)
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 18
19. Jetzt mal ein konkretes Beispiel...
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 19
20. Rationale Zahlen
n
Sind Zahlen der Form d mit n ∈ Z, d ∈ N ("‘Brüche"’)
...bauen wir also eine Klasse:
class Rational(n: Int, d: Int)
Codebeispiel aus Odersky et al., Programming in Scala, 2008
Mit verständlicher Ausgabe und Kontrolle der Eingabe:
class Rational(n: Int, d: Int) {
require(d != 0)
override def toString = n +"/"+ d
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 20
21. Hinzufügen der Addition5
class Rational(n: Int, d: Int) {
require(d != 0)
val numer: Int = n
val denom: Int = d
override def toString = numer +"/"+ denom
def add(that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
5 Geht eleganter, wird gleich noch ausgebaut...
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 21
22. Hilfskonstruktor für n
1
class Rational(n: Int, d: Int) {
require(d != 0)
val numer: Int = n
val denom: Int = d
def this(n: Int) = this(n, 1)
override def toString = numer +"/"+ denom
def add(that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 22
23. GGT zur Vereinfachung des Bruchs
class Rational(n: Int, d: Int) {
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
def add(that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
//...
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 23
24. ’Operatoren’
class Rational(n: Int, d: Int) {
//...
def + (that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
def * (that: Rational): Rational =
new Rational(numer * that.numer, denom * that.denom)
def <(that: Rational) = this.num * that.denom <
this.denom * that.num
//... usw.
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 24
25. Unäre ’Operatoren’ und Backticks
class Rational(n: Int, d: Int) {
//...
def unary_~() = new Rational(denom, num)
def unary_-() = new Rational(-num, denom)
//Sowas hier geht auch:
def `ha<ll$>$%o !`: Int = 2
//... usw.
}
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 25
26. ’Operatoren’ für andere Typen
class Rational(n: Int, d: Int) {
//...
def + (i: Int): Rational =
new Rational(numer + i * denom, denom)
//... usw.
}
Codebeispiel aus Odersky et al., Programming in Scala, 2008
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 26
27. Implizite Typumwandlung
class Rational(n: Int, d: Int)//...
object TestRationals {
implicit def intToRational(x: Int) = new Rational(x)
def main(args: Array[String]) {
val oneHalf = new Rational(1, 2)
val twoThirds = new Rational(20, 30)
println(oneHalf + twoThirds)
println(oneHalf < twoThirds)
println(new Rational(3))
println(~oneHalf)
println(oneHalf * 5 - oneHalf)
println(5 * oneHalf)
}
}
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 27
28. Vorsicht! "‘[...]creating methods with operator names and
defining implicit conversions can help you design
libraries for which client code is concise and easy to
understand. Scala gives you a great deal of power
to design such easy-to-use libraries, but please
bear in mind that with power comes
responsibility. [...]
Conciseness will often be a big part of that
readability, but you can take conciseness too far. By
designing libraries that enable tastefully
concise and at the same time
understandable client code, you can help
those client programmers work productively."’
(p. 113, Odersky et al., Programming in Scala, 2.
Ausgabe)
Image source: user mostuncool, http://www.flickr.com/photos/mostuncool/102762603/
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 28
29. ’Pimp-My-Library’ Pattern
import java.io._
import scala.io._
class RichFile(file: File ) {
def text = Source.fromFile( file ).mkString
def text_=( s: String ) {
val out = new PrintWriter( file )
try{ out.println( s ) }
finally{ out.close }
}
}
object RichFile {
implicit def enrichFile( file: File ) = new RichFile( file )
}
//...
val f = new File("/tmp/example.txt")
f.text = "hello world"
Von: http://stackoverflow.com/questions/6879427/scala-write-string-to-file-in-one-statement
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 29
30. Praxis
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 30
31. Tools
• Eclipse-Integration: http://www.scala-ide.org
• Test-Frameworks: JUnit etc. (Bytecode-kompatibel)
• S CALA-Konsole
• Interessante Frameworks, z.B. L IFT (http://liftweb.net/)
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 31
32. Maven-Integration6
<!-- ... -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.9.0</version>
</dependency> <!-- ... -->
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
</plugin> <!-- ... -->
6 Benötigt Repository http://scala-tools.org/repo-releases
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 32
33. Scripting
#!/bin/sh
exec scala "$0" "$@"
!#
import java.io._
import scala.collection.mutable.Set
if(args.size < 2) {
println("Usage: addAccess hgrc_file user1 [user2 ...]")
sys.exit(0)
}
val singleLines = io.Source.fromFile(args(0)).mkString.split("n")
val editedLines = singleLines.map(l => if(matches(l)) update(l) else l)
val out = new PrintWriter(new File(args(0)))
try{ out.println(editedLines.mkString("n")) } finally{ out.close }
def matches(line:String) = line.matches(".*allow_(read|push).*=.*")
def update(line:String) = {
val splitLine = line.split("=")
val elems = Set() ++ splitLine(1).split(",").map(_.trim) ++ args.toList.tail
splitLine(0).trim + " = " + elems.mkString(", ")}
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 33
35. Zusammenfassung
• Scala ist JVM-kompatibel
• Scala ’wächst’ mit den Aufgaben
• Scala ist ideal, um als Java-Programmierer FP zu lernen/anzuwenden
• Scala bietet Java gegenüber viele kleine Verbesserungen, kann also auch
ohne FP-Ambitionen genutzt werden
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 35
36. Interessante Features die es nicht in den Überblick
geschafft haben
• Actors (einfache nebenläufige Programmierung)
• Traits (Interfaces mit Logik!)
• Pattern Matching
• Annotationen
• Arrays
• DSLs bauen (siehe Actors)
• Unterstützung von XML & Regex
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 36
37. Alternativen
Java ohne Boilerplate: http://www.eclipse.org/Xtext/xtend
’Echte’ funktionale Programmierung auf der JVM: http://clojure.org
Scala in einfach:
http://confluence.jetbrains.net/display/Kotlin
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 37
38. Material zum Weitermachen
• The busy Java developer’s guide to Scala:
http://www.ibm.com/developerworks/java/library/
j-scala01228
• Programming Scala:
http://ofps.oreilly.com/titles/9780596155957/
• Scala School:
http://twitter.github.com/scala_school/
• 99 Scala Problems:
http://aperiodic.net/phil/scala/s-99/
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 38
39. Lizenzen
• Bilder von Folie #2 & #28: Creative Commons BY-NC-SA 2.0
• Alle eigenen Inhalte ebenso
Siehe: http://creativecommons.org/licenses/by-nc-sa/2.0/deed.de
16. November 2011 c 2011 UNIVERSITÄT ROSTOCK | FAKULTÄT FÜR INFORMATIK UND ELEKTROTECHNIK 39