Programmieren in Scala - informatik.uni-augsburg.de · Motivation Aus Sicht unseres...

21
Programmieren in Scala 17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 232 / 300

Transcript of Programmieren in Scala - informatik.uni-augsburg.de · Motivation Aus Sicht unseres...

Programmierenin

Scala

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 232 / 300

Motivation

• Aus Sicht unseres Sotwaretechnik-Lehrstuhls:Scala ist eine der derzeit modernsten Programmiersprachen

• KIV wird derzeit nach Scala portiert (fast fertig)

• KIV ist dann mit Scala und Java (GUI) programmiert.

• Scala unterstutzt Konzepte die vieles mit den Konzepten derKIV-Spezifikationen gemeinsam haben.

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 233 / 300

Was ist Scala?

• Scala ist entwickelt an der Uni Lausanne von Prof. Oderskyhttp://www.scala-lang.org

• Viele Dokus (Tutotial, etc.) kann man dort finden

• Eclipse-IDE: //http://www.scala-ide.org

• Scala ist eine objektorientierte Sprache

• Alle Konzepte von Java (Methoden, Klassen, Vererbung etc.) gibt es(z.T. in verbesserter Form) auch in Scala

• Scala wird in ByteCode der JVM compiliert

• Scala unterstutzt auch die Konzepte aus funktionalen Sprachen(Higher-Order Funktionen Pattern Matching etc.)

• Die Syntax von Scala ist etwas anders, und deutlich verbessert

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 234 / 300

Scala: Typen

• Scala kennt wie Java Klassen und generische Klassen

• Oberster Typ ist Any statt Object

• Scala kennt keine primitiven Typen:• statt int und Integer gibt es nur Int• analog: bool, Boolean ⇒ Boolean, array, Array ⇒ Array

• generische Typen werden mit eckigen Klammern geschrieben:Array[Int] statt Array<Int>

• Array-Zugriff mit runden Klammern a(i) (statt a[i])

• Fest vordefiniert sind Tupel mit (fur 3-Tupel) Typ (A,B,C). Siewerden auch als (a,b,c) konstruiert. Die Felder werden z.B. mit(a,b,c). 2 selektiert (liefert b)

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 235 / 300

Scala: Methodendefinition

• Scala kennt wie Java statische und dynamische Methoden

• Java:

type method(argty1 arg1, argty2 arg2, ...){

body

}

• Scala:

def method(arg1:argty1,arg2:argty, ...):type = {

body

}

• Der Typ void heisst Unit in Scala

• Methoden ohne Resultat konnen vereinfacht als

def method(arg1:argty1, ... ) { body }

geschrieben werden (kein Typ und kein Gleichheitszeichen)

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 236 / 300

Scala: Methodenaufruf

• Aufruf wie in Java fur statische und dynamische Methodentype . smethod (arg1, arg2, . . . )object . dmethod (arg1, arg2, . . . )

• Bei Methoden ohne Argumente durfen Leerklammern weggelassenwerden (auch schon bei der Definition)

• Konvention: Leerklammern weglassen gdw. keine Seiteneffekte:z.B. Selektoren (“getter”) und Tests: list.length, list.isEmpty

• Vorteil: Feldzugriff kann lokal auf get-Methode (gleichen Namens)geandert werden (keine Anderung in anderen Klassen!)

• Dynamischen Methoden mit einem Argument darf man mitobject method arg aufrufen (Infix: weder Punkt noch Klammern!)

• Vorteil: +, * etc. haben keine Sonderrolle mehr(sie konnen auch uberladen werden).

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 237 / 300

Ausprobieren von Scala

• Scala kann man wie Java compilieren und ein Programmmain(arglist:Array[String]):Unit in einem object ausfuhren.

• Scala kann aber auch mit einem Kommandozeileninterpreter(entweder von innerhalb Eclipse oder standalone) bedienen

• Aufruf von scala gibt scala>-prompt

• Eintippen von Ausdrucken wertet diese aus

scala> "Hello" + " World!"

"Hello World!"

scala> 3 + 4

7

scala> new Array(4,5).length

2

scala> new Array(5,6)(1)

6

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 238 / 300

Scala: Felder und lokale Variablen

• Scala unterscheidet bei Feldern und Variablen uberschreibbare (var)und nicht uberschreibbare (val; Java: final)

• nicht uberschreibare Felder/Variablen val x:Int = 5

• uberschreibare Felder/Variablen var x:Int = 5

• Scala implementiert eine Typinferenz:Fur die meisten Variablen und initialisierten Felder kann dieTypangabe wegfallen.

• Fur das obige Beispiel: val x = 5 ist ok

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 239 / 300

Scala: Methodenrumpfe

• Scala kennt keinen Unterschied zwischen Statement und Expression.

• Statements sind einfach Expressions vom Typ Unit

• Deshalb ist mischen erlaubt, z.B.:

val x = if (y > 5) { val y = 3; y + 2} else 5

• Der ?-Operator von Java ist in Scala uberflussig

• In Scala werden Strichpunkte nur benotigt, wenn zwei Statementsauf derselben Zeile stehen (sehr selten)

• Zeilenumbruch fugt (wo sinnvoll) implizit einen Strichpunkt ein

• Wenn return expr das letzte Statement einer Methode ist, darf nurexpr geschrieben werden.

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 240 / 300

Scala: Beispele fur Methoden

• Fakultatsfunktion:

def fac(x:Int):Int = {if (x == 0) 0 else fac(x - 1)}

• Lange (wie in Listenklasse vordefiniert):

def length:Int = {if (isEmpty) 0 else tail.length + 1}

• Letztere Funktion wurde in Java so aussehen:

int length() {if (isEmpty) return 0;

else return tail.length() + 1;}

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 241 / 300

Scala: Klassendefinitionen (1)

• Java Klassen enthalten sowohl statische als auch dynamischeMethoden

• Scala teilt die Methoden auf in dynamische in der Klasse undstatische, die im sog. companion object gleichen Namens stehen

• Beide mussen in dieselbe Datei, eines von beiden darf fehlen

• Wenn nur object ⇒ Singleton.

object A {

def staticmethod(arg:Int):Int = { 2 * arg }

}

class A {

val field = 5

def dynamicmethod(arg:Int):Int = { this.field + arg}

}

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 242 / 300

Scala: Klassendefinitionen (2)

• Java Klassen haben immer einen (haufig nutzlosen) nullstelligenKonstruktor

• meist muss einer definiert werden, der einfach nur Felder initialisiert.

• In Scala stattdessen: Felder, die im Konstruktor initialisiert werdensollen, als Argumente der Klasse. Kein nullstelliger Konstruktor.

class A(val field1:Int, var field2:Int) {...}

ergibt als moglichen Konstruktoraufruf new A(3,5). Ein nullstelligerKonstruktoraufruf ist nicht moglich.

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 243 / 300

Scala: Abstrakte Datentypen (1)

Scala unterstutzt freie Datentypen analog zu KIV-Specs.Beispiel: arithmetische Ausdrucke.

sealed abstract classed AExp

case class Binop(val e1:AExp, val str:String, val e2:AExp) extends AExp

case class Unop(val str:String, val e:AExp) extends AExp

case class Val(val v:Int) extends AExp

case class Var(val id:String) extends AExp

erlaubt zu schreiben:

Binop(Var("x"),"+",Unop("-",Val(4))))

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 244 / 300

Scala: Abstrakte Datentypen (2)

• Ein abstrakter Datentyp besteht aus einer abstrakten(Summen-)Klasse (AExp) und einer Anzahl Unterklassen(Summanden; hier Binop, Unop, Val, Id)

• Alle Klassen werden zusammen in die Datei AExpder Summenklasse geschrieben

• sealed ⇒ keine (weiteren) Unterklassen in anderen Dateien

• case class: erlaubt Konstruktoraufruf ohne Schlusselwort new(und Pattern matching; siehe spater)

• Die Felder sind meist nicht schreibbar (val),sie werden nur vom Konstruktor initialisiert(“immutable” datatype; entspricht algebraischen Datentypen).

• Gleichheit (i.e. ==) vergleicht case classes strukturell (nicht wie inJava auf Referenz-Gleichheit).

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 245 / 300

Scala: Listen (1)

Listen sind ein vordefinierter freier Datentyp

sealed abstract class List[+A]

case class ::[A](val head:A, tail:List[A]) extends List[A]

case object Nil extends List[Nothing]

erlaubt Konstruktion mit 1::2::Nil

Bem: eigentlich ::(1,::(2::Nil)), aber “::” ist auch eine Infixfunktion auf Listen, die mit

Doppelpunkt endet. Solche Infixfunktionen drehen die Argumentreihenfolge um!

Alternativ: List(1,2) (durch Aufruf der statischen Methode List mitvariabler Argumentzahl im companion object der Klasse List)

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 246 / 300

Scala: Listen (2)

• Listen erlauben kein Uberschreiben des head oder tail.

• Listen sind kovariant (das bedeuet das + vor dem Typparameter):jedes x:List[Int] ist auch ein x:List[Any]jedes x:List[Binop] ist auch ein x:List[AExp]

• allgemein x:List[type1] ist Subtyp von x:List[type2] falls type1 einSubtyp (Unterklasse) von type2 ist.

• Arrays sind dagegen nicht kovariant (weil modifizierbar)

• Nothing ist der leere Typ ohne jedes Element (Subtyp von jedemTyp). Nil ist deshalb vom Typ List[type] fur jeden Typ type

• Listen haben viele vordefinierte Funktionen, u.a. ++ (append), x(i)(get fur das i-te Element, 0-basiert); siehe scaladoc

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 247 / 300

Scala: Pattern Matching

• Scala erlaubt Pattern Matching fur ADTs• match verallgemeinert Java’s switch.• Methode allids (in Klasse AExp) sammelt

alle vorkommenden Variablen des Ausdrucks• Funktion ++ hangt Listen aneinander.• Ein Underscore steht fur wildcard (beliebig)

def allids:List[String] = {

this match {

case Var(id) => List(id)

case Binop(e1, ,e2) => e1.allids ++ e2.allids

case Unop( ,e0) => allids(e0)

case Val( ) => Nil

}

}

Binop(Var(”x”),”+”,Val(4)).allids ergibt List(”x”)

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 248 / 300

Scala: Higher-Order Funktionen

• Scala erlaubt Higher-Order Functions,i.e. Funktionen, die Funktionen als Argumente bekommen.

• Funktionstypen werden A => B geschrieben.

• Beispiel: Funktion map (in Klasse List[A] definiert)wendet eine Funktion f auf alle Listenelemente an

def map[B](f:A => B):List[B] = {

this match { Nil => Nil

x :: xs => f(x) :: xs.map(f)

}}

oder alternativ:

def map[B](f:A => B):List[B] = {

if (isEmpty) Nil else f(head) :: tail.map(f)

}

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 249 / 300

Scala: lambda-Abstraktionen

• Das Funktionsargument von map kann eine Funktion sein, die mitdef definiert wurde

• Da die Funktion meist nur einmal verwendet wird, gibt es auch dieMoglichkeit, sie als lambda-Abstraktion anzugeben

• x:Int => x + 1 ist die Funktion, die eins addiert

• (x:Int,y:Int) => x + y ist die Additionsfunktion

• Verwendung z.B mit map:List(1,2,3).map((x:Int) => 2 * x) ergibt List(2,4,6)

• Kurzschreibweise: e(_) statt (x:Int => e(x))

(manchmal ist Typangabe notwendig: e(_:Int)

• Beispiel: List((1,2),(4,5)).map(_._1) == List(1,4)

(mit Selektor . 1 fur Paare)

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 250 / 300

Scala: Datentyp Map

• Eine Map bildet endlich viele Schlussel (keys) auf Werte (values) ab.

• Analog zu Liste von Paaren, aber keine doppelten Schlussel

• Paare kann man sowohl mit (a,b) als auch mit a -> b konstruieren.

• Konstruktion aus Paaren mit Map("x" -> 3, "y" -> 4)

• Das letzte zahlt: Map("x" -> 3, "x" -> 4) == Map("x" -> 4)

• Zugriff uber Map("x" -> 3, "y" -> 4)("x") ergibt 3

• Addieren: Map("x" -> 3) + ("y" -> 4) ergibtMap("x" -> 3, "y" -> 4)("x")

• Loschen mit Map("x" -> 3, "y" -> 4) - "x" gibtMap("y" -> 4)

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 251 / 300

Scala: viele weitere Features

Scala hat noch viele andere Features, auf die wir hier nicht eingehen:

• lazy Funktionen und Felder

• interfaces erweitert scala zu traits.Diese durfen auch Code definieren.

• implizite Argumente

• selbstdefiniertes Pattern Matching

• erweiterte generische Syntax fur Schleifen

• . . .

17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 252 / 300