Scala Java-Nachfolger oder akademisches Experiment? KONTROLLABSTRAKTION (NEUE KONTROLLSTRUKTUREN) Gliederung Einleitung Nutzung der Standard Kontrollstrukturen if – else, for, do – while, while, match, try – catch Spezielle Kontrollstrukturen z.B. exists Die verfügbaren Mittel First-class-functions , Higher-order-functions, Currying, By-name-Parameter Neue Kontrollstrukturen Beispiele neuer Kontrollstrukturen Fazit Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 2 Einleitung Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit „Kontrollstrukturen (Steuerkonstrukte) werden in imperativen Programmiersprachen verwendet, um den Ablauf eines Computerprogramms zu steuern. Eine Kontrollstruktur gehört entweder zur Gruppe der Verzweigungen oder der Schleifen. Meist wird ihre Ausführung über logische Ausdrücke der booleschen Algebra beeinflusst…“ (Quelle: Wikipedia) Scala hat nicht viele Kontrollstrukturen Integrierte Bestandteile sind so implementiert, dass neue, eigene erstellt werden können Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 3 Standard Kontrollstrukturen Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Scala bietet folgende integrierte, elementare Kontrollstrukturen Sie lassen sich benutzen, um eigene zu kreieren if-else while, do-while for match try-catch Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 4 Nutzung von if-else Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit In Scala hat die if, else - Kontrollstruktur einen beliebigen Rückgabewert ( in Java nicht) So kann in Scala der Inhalt einer Variablen von einer Bedingung abhängig gemacht werden. String t = ""; if (checkValue % 2 == 0) t="gerade"; else t = "ungerade"; System.out.println("checkValue "+ checkValue +" ist "+ t) ; val check = if (checkValue % 2 == 0) log(checkValue) else "ungerade" println("checkValue "+ checkValue +" ist "+ check) Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 5 Nutzung von Schleifen-KS Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Kontrollstruktur „while“ gibt ausschließlich ein Objekt vom Typ Unit zurück Nicht geeignet für eigene Kontrollstrukturen Äquivalent dazu verhält sich „do – while“ Mit „for“ kann ein Ergebnis über „yield“ zurückgegeben werden Umfangreiche Prüfmechanismen machen die Schleifen zu einem mächtigen Werkzeug In Scala (2.7) kein „break“ oder „continue“ Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 6 Beispiele „while“ & „for“ Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit var index = 0; val testString = “TestString“ val back = while (index < testString.length) { println(testString(index)) index += 1; }; println(back) // Unit() def even(from: Int, to: Int): List[Int] = for (i <- List.range(from, to) if i % 2 == 0) yield i Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 7 break und continue Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit object BreakLoop { object Break extends RuntimeException; object Continue extends Exception; def break { throw Break } def continue { throw Continue } def whileTrue(block: => Unit) { try { while (true) try { block } catch { case Continue => } } catch { case Break => } } def whileTrue(condition: => Boolean) (block: => Unit) { try { while (condition) try { block } catch { case Continue => } } catch { case Break => } } } Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 8 Beispiel break & continue Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit import util.BreakLoop._ object TestBreak extends Application { var i = 0; whileTrue { i += 1 if (i < 3) continue if (i >= 5) break } } Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 9 Wiederholung (match) Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit match ist das Scala Gegenstück zu Java's switch, aber weit aus mächtiger Mit Hilfe von match können in Scala auch Objekte zur Fallbestimmung herangezogen werden Implizites break def matchTest(x: Any): Any = x match { case 1 => "one“ case "two" => 2 case "two" => 2 // Fehler: Unreachable Code case y: Int => "scala.Int" } Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 10 Spezielle Kontrollstrukturen Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Scala benutzt implizit eigene Mittel, für Erweiterungen z.B. Methode exists für (List, Set, Array und Map ) Standardlösung zum finden eines Objekts in einer Collection def containsNeg(nums: List[Int]): Boolean = { var exists = false for (num <- nums) if (num < 0) exists = true exists } Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 11 Spezielle Kontrollstrukturen Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Standardlösung zum finden eines Objekts in einer Collection def containsNeg(nums: List[Int]): Boolean = { var exists = false for (num <- nums) if (num < 0) exists = true exists } Lösung mittels higher-order-functions def containsNeg(nums: List[Int]) = nums.exists(_ < 0) Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 12 Die Mittel - first-class-functions Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Thema des letzten Vortrages Funktionen können als Code (function literals) niedergeschrieben oder als Funktionswerte (function values ) zur Laufzeit übergeben werden Bsp: (x : Int) => x + 1 Das “=>” bewirkt, das die Funktion den linken Teil (irgendein Int “x” ) in den rechten Teil (x + 1) umwandelt (Mapping) Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 13 Die Mittel – higher-order-functions Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Funktionen, die Funktionen als Parameter haben können Vorteil: Hilft bei der Minimierung von doppeltem Code Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 14 Beispiel Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit class FileMatcher { private def filesHere = (new java.io.File(".")).listFiles private def filesMatching(matcher: String => Boolean) = for (file <- filesHere; if matcher(file.getName)) yield file def filesEnding(query: String) = filesMatching(_.endsWith(query)) def filesContaining(query: String) = filesMatching(_.contains(query)) def filesRegex(query: String) = filesMatching(_.matches(query)) } Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 15 Die Mittel – Currying Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit „Currying ist die Umwandlung einer Funktion mit mehreren Argumenten in mehrere Funktionen mit je einem Argument…“ (Quelle: Wikipedia) Wird benutzt um abstrahierte Kontrollstrukturen wie Spracherweiterungen aussehen zu lassen Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 16 Die Mittel – Currying Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit def plainOldSum(x: Int, y: Int) = x + y scala> plainOldSum(1, 2) res4: Int = 3 def curriedSum(x: Int)(y: Int) = x + y scala> curriedSum(1)(2) res5: Int = 3 Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 17 Die Mittel - By-Name Parameter Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Möglichkeit Prüfbedingungen aufzurufen, ohne sie auszuwerten Bsp. Assertion Standard var assertionEnabled = false def boolAssert(predicate : Boolean) = if(assertionEnabled && !predicate) throw new AssertionError boolAssert(5/0 == 0) Führt zu: Exception in thread "main" java.lang.ArithmeticException: / by zero Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 18 Die Mittel - By-Name Parameter Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Bei Aufruf mit By-Name var assertionEnabled = false def byNameAssert(predicate : => Boolean) = if(assertionEnabled && !predicate) throw new AssertionError byNameAssert(5/0 == 0) gibt nichts zurück Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 19 Neue Kontrollstrukturen Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Möglichkeit eigene Kontrollstrukturen zu definieren syntaktisch wie integrierte Kontrollstrukturen First-class-Funktionen sind dabei das wichtigste Werkzeug Oderskys Empfehlung: Bei jedem, sich wiederholenden control pattern, sollte man darüber nachdenken diesen als neue Kontrollstruktur zu implementieren Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 20 Einfache Beispiele Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Function Value Parameter of Function Value converted in Double def twice(op: Double => Double, x: Double) = op(op(x)) Double Parameter scala> twice(_ + 1, 5) Result: Double = 7.0 Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 21 Einfache Beispiele Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Eigene MyWhile-Schleife – aber wie???? 1. Was wird benötigt? Methodenname Bedingung, die überprüft wird Methodenrumpf, der ausgeführt werden kann 2. Welche Möglichkeiten sind geeignet? first-class & higher-order Funktionen var x = 0 by-name-Parameter myWhile (x < 10) { currying println(x) x=x+1 } Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 22 Einfache Beispiele Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Methodendefinition var x = 0 myWhile (x < 10) { println(x) x=x+1 } def myWhile(„Bedingung“ , „AusführbarerCode“) … Darf die Bedingung ausgewertet werden? Nein! By-Name-Parameter def myWhile(„Bedingung“: => , „AusführbarerCode“) … Typ für den Funktionswert sicherstellen!!! def myWhile(condition: => Boolean , „AusführbarerCode“) … Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 23 Einfache Beispiele Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit function-values setzen var x = 0 myWhile (x < 10) { println(x) x=x+1 } def myWhile(condition: => Boolean , operation ) … Egal, welcher Code ausgeführt werden soll kein spez. Rückgabetyp Unit def myWhile(condition: => Boolean , operation: => Unit ) Probleme: Aufruf erlaubt nur einen Funktionswert, als Parameter Currying ermöglicht Austausch der Klammern def myWhile(condition: => Boolean) (operation: => Unit ) Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 24 Einfache Beispiele Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Codeausführung über Rekursion def myWhile(condition: => Boolean, operation: => Unit){ operation if(condition){ myWhile(condition, operation)} } Der Aufruf – wie gewünscht var x = 0 myWhile (x < 10) { println(x) x=x+1 } Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 25 Loan Pattern Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Loan ( = die Leihe) def withPrintWriter(file : File)(op : PrintWriter => Unit) { val writer = new PrintWriter(file) try{ op(writer) } finally { writer.close() } } Look and Feel -> Ersetzen von “(“ durch “{“ Nur möglich bei einem Argument Currying withPrintWriter(file) { writer => writer.println(new java.util.Date) } Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 26 Generische Rückgabe Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit value expressions können automatisch in Funktionen konvertiert werden def unless[A](condition: Boolean, ifTrue : => A, ifFalse : => A) = if (condition) ifTrue else ifFalse unless(true, throw new Error, "Hello!") ⇒"Hello!“ Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 27 Eigene Kontrollstrukturen Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Closeable-Objekte immer schließen object ClosingTest { type CloseType = { def close() } def manage(resource: CloseType) (block: => Unit) = { try{ block } finally { println("Closing...") resource.close() println("Closed!!! ") }} def main(args : Array[String]) : Unit ={ val reader = new BufferedReader(new FileReader("src\\test.txt")) manage(reader) { var line: String = reader.readLine while (line != null) { println(line) line = reader.readLine} }}} Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 28 Fazit Gliederung •Einleitung •Standard KS •Spezielle KS •Mittel •Neue KS •Fazit Kurzer Code erschwert debuggen Code-Stil wird schnell verwirrend Unglaublich mächtig, jedoch nicht mehr lesbar Unübersichtlicher Code erschwert Typsicherheit Ist kürzerer Code immer der Bessere? Kontrollabstraktion (neue Kontrollstrukturen) -- Florian Syska, Christian Wilhelmi 04.05.2010 29 Quellen: Oderskys: Programming in Scala http://daily-scala.blogspot.com http://timpt.de/it/topic141.html http://www.scala-lang.org/ http://en.wikipedia.org http://www.ibm.com/developerworks/java/library/j-scala03268.html http://termos.vemod.net/implementing-your-own-control-structures-inscala VIELEN DANK FÜR IHRE AUFMERKSAMKEIT!