4. Einleitung
• Scala vereint objektorientierte und funktionale Konzepte
• Scala überzeugt durch kompakte Syntax, geringe Redundanz, hohe
Ausdrucksstärke
• Stichwort Inferenz: Typinferenz, Semikoloninferenz
• Entwickelt von Martin Odersky und seinem Team seit 2001 an der EPFL in der
Schweiz
• War Doktorand von Niklaus Wirth, dem Erfinder von Pascal
Montag, 11. Februar 13
4
6. Programmiermodell
• Scala-Programme laufen in der
JVM (auch unter .NET)
3)
4)
• Quellcode in Textdateien
• Java-Konventionen empfohlen,
aber kein Muss
• Klassen in gleichnamigen
Dateien
• Paketstruktur entspricht
Verzeichnisstruktur
• zahlreiche Bibliotheken
Montag, 11. Februar 13
5)
6
10. Klassen
class Square(var length: Int) {
def printInfo() {
println("Square with length " + length)
}
def area() = length * length
def calc3DVolume(height: Int) : Int = {
area * height
}
}
Montag, 11. Februar 13
10
11. Objekte
• Objekte als Instanzen von
Klassen
val s = new Square(2)
s.printInfo
println(s.length)
object Figure {
var count: Int = 0
• Objekte als Singleton-/
Companion-Objekte, vgl.
static-Deklaration in Java
def printFiguresInfo() {
println("Number of figures: "
+ count)
}
}
class Figure(name: String) {
Figure.count += 1
println("New figure: " + name)
}
Montag, 11. Februar 13
11
12. Anweisungen
• Zwei Formen für
Methodenaufrufe
• Arithmetische Operatoren sind
als Methoden implementiert
• Präzedenz anhand des ersten
Zeichens des
Methodennamens, Tabelle
val
val
val
val
a
b
c
d
=
=
=
=
1
2
a.+(b)
a + c
val x = this.test(c, d)
val y = this test (a, b)
def test(a: Int, b: Int): Boolean =
a > b
• Ausname: Methodenname
endet mit =
(z.B. +=, <=, >= etc.)
Montag, 11. Februar 13
12
13. Kontrollstrukturen
• imperativ (Rückgabetyp Unit)
• while
def whileLoop() {
var count = 0
while (count < 10) {
println(count)
count += 1
}
}
• do-while def doWhileLoop() {
• funktional (Rückgabetyp nutzbar)
• if-else
• for
• try-catch-finally
• match-case
var count = 0
do {
println(count)
count += 1
} while (count < 10)
}
Montag, 11. Februar 13
13
15. Kontrollstrukturen - for
for (
i <- 1 to 50 if i % 2 == 0;
k <- divisors(i, 2) if k % 2 != 0;
l = -k
) {
println("Odd divisor of even " + i + ": " + k +
" (negative: " + l + ")")
}
Montag, 11. Februar 13
15
17. Immutable vs. Mutable
Immutable:
import scala.collection.immutable.Map
object ImmutableDemo {
val x = Map[Int, String]()
x += (3 -> "three") //does not compile
val i = 3
i = 4 //does not compile
}
Mutable:
import scala.collection.mutable.Map
class MutableDemo {
val x = Map[Int, String]()
x += (3 -> "three") //works!
var i = 3
i = 4 //works!
}
Montag, 11. Februar 13
17
18. Typsystem
• Strenges Typsystem
• Typen werden durch Klassen und Traits definiert
• Implizite Typumwandlung
object ImplicitDemo extends App {
implicit def string2mystring(string: String): MyString =
new MyString(string)
class MyString(string: String) {
def insertBlanks(): String = string.toList.mkString(" ")
}
println("ABCDEFG".insertBlanks)
//println(string2mystring("ABCDEFG").insertBlanks)
}
Montag, 11. Februar 13
18
20. Parametrischer Polymorphismus
class
class
class
class
class
UpperBound[T <: AnyRef]
LowerBound[T >: String]
NonVariant[T]
Covariant[+T]
ContraVariant[-T]
object ParametricPolymorphismDemo extends App {
val upperBound = new UpperBound[String]
val lowerBound = new LowerBound[AnyRef]
val nonVar = new NonVariant[String]
val coVar: Covariant[Object] = new Covariant[String]
val contraVar: ContraVariant[String] = new ContraVariant[Object]
}
Montag, 11. Februar 13
20
21. Dynamische Komponente
def instanceOfVersion(someObject: Any): String = {
(if (someObject.isInstanceOf[String])
someObject.asInstanceOf[String]
else
"no string") + " (instanceOf)"
}
def matchVersion(someObject: Any): String = {
(someObject match {
case s: String => s
case _: Any => "no string"
}) + " (match)"
}
Montag, 11. Februar 13
21
22. Überladen von Methoden
• Überladen erfolgt durch Definitionen mit demselben Methodennamen
und unterschiedlichen Parameterlisten
def getAsString(value: Double, maxDigits: Int) = { ... }
def getAsString(value: Int) = { ... }
Montag, 11. Februar 13
22
23. Überschreiben, dynamisches Binden von
Methoden
• Überschreiben erfolgt durch
Schlüsselwort override
• Dynamisches Binden erfolgt
beim Aufruf der Methode
printLevel() auf dem Alias x vom
Typ BaseClass, der auf eine
Instanz vom Typ SubClass1
zeigt
• Ausgeführt wird die in
SubClass1 definierte Methode,
welche die Methode in
BaseClass überschreibt
Montag, 11. Februar 13
abstract class BaseClass {
def printLevel() {
println("Base")
}
}
class SubClass1 extends BaseClass {
override def printLevel() {
println("Sub")
}
}
object OverrideDemo extends App {
val x: BaseClass = new SubClass1
x.printLevel //-> Sub
}
23
25. Multi-Threading
object ActorDemo extends App {
val client = actor {
loop {
react {
case Start =>
server ! Request
case Response =>
println(
"clnt: Resp received")
exit()
}
}
}
client.start
server.start
case object Start
case object Request
case object Response
val server = actor {
loop {
react {
case Request =>
println(
"srv: Req received")
sender ! Response
exit()
}
}
}
Montag, 11. Februar 13
client ! Start
}
25
26. Metaprogrammierung
• Angabe von Annotations durch @-Zeichen auf Klassen, Methoden, Feldern,
Parametern
• Annotation => Konstruktoraufruf, ermöglicht Angabe von Parametern aus
dem aktuellen Gültigkeitsbereich
• Beispiele: @serializable, @unchecked
• Reflection-API von Java muss zur Auswertung und Implementierung eigener
Annotations genutzt werden
Montag, 11. Februar 13
26
27. Traits
• Mächtiger als Java-Interfaces
• Ermöglichen die Wiederverwendung von Funktionalität ohne
Vererbungszwang
• Mehrfachvererbung ohne die bekannten Nachteile
10)
Montag, 11. Februar 13
27
28. Traits - Beispiel
class Logger { def log(string: String) { println(string) } }
trait InfoPrefix extends Logger {
abstract override def log(string: String) {
super.log("[Info] " + string)
}
}
object TraitDemo extends App {
val infoLogger = new Logger with InfoPrefix
infoLogger.log("This is info")
//-> [Info] This is info
}
Montag, 11. Februar 13
28
29. Traits - Linearisierung
• Beispiel aus dem Buch von
Martin Odersky zeigt das
Prinzip zur Vermeidung der
Mehrdeutigkeit vererbter
Methoden („Diamond Problem“)
• super-Aufrufe werden
dynamisch gebunden, statt
statisch wie bei „normaler“
Vererbung
class
trait
trait
trait
class
Montag, 11. Februar 13
11)
Animal
Furry extends Animal
HasLegs extends Animal
FourLegged extends HasLegs
Cat extends Animal with Furry with FourLegged
29
30. apply()-Methode
class Formula(f: (Int => Int)) {
def apply(x: Int) = f(x)
}
object Formula {
def apply(f: (Int => Int)) = new Formula(f)
}
val formula = Formula(x => x * x)
println(formula(2))
Montag, 11. Februar 13
30
33. Bewertung
• kompakter als Java
• Lösungen sehen häufig aus, als
wären sie Bestandteil des
Sprachumfangs, dabei "nur"
Bibliotheken
• saubere Programme durch
"immutable" Konzept, Parallelität
möglich
• Konsistenz des Sprachentwurfs
Montag, 11. Februar 13
• leicht zu erlernen, wenn
objektorientierte und funktionale
Grundkonzepte bekannt sind
• sehr angenehme Sprache
Bewertung:
1(Tool-Unterstützung noch nicht
auf dem Niveau von Java)
33