Pimp My Scala – Effektive Scala Nutzung durch typische Entwurfsmuster OOP 2012 Andreas Tönne, NovaTec GmbH Direktor R&D der NovaTec GmbH Standort Frankfurt am Main © NovaTec 12.06.2013 2 Übersicht Blitzkurs Scala Einführung in typische Scala Pattern Basierend auf ausgewählten Schlüsselfeatures von Scala Beispiele für idiomatisch korrekte Pattern Einschließlich Pimp My Library, Cake und Type Classes Implementierungsskizzen und Erläuterungen Umfangreiche Beschreibungen und Codebeispiele unter scala.novatec-gmbh.de © NovaTec 12.06.2013 3 Design Pattern Wir alle wissen was Pattern sind? GoF: Gamma, Helm, Johnson, Vlissides: „Entwurfsmuster“ (Addison-Wesley, 1996) Pattern sind keine Erfindung sondern einer Entdeckung! „Keines der Entwurfsmuster … beschreibt neuartige Entwürfe. (…) Trotzdem wurden viele dieser Entwürfe noch nie dokumentiert. Sie gehören entweder zum Allgemeinwissen … oder sie sind Teil erfolgreicher … Systeme.“ „Die Entwurfsmuster … sind Beschreibungen zusammenarbeitender Objekte und Klassen, die maßgeschneidert sind, um ein allgemeines Entwurfsproblem in einem bestimmten Kontext zu lösen.“ © NovaTec 12.06.2013 4 Design Pattern Design Pattern entstehen im Kontext der Möglichkeiten einer Programmiersprache Umgehen unerwünschte Eigenarten der Sprache Bilden zusammengesetzte wünschenswerte neue Sprachkonstrukte Dokumentieren idiomatisch guten Einsatz der Sprache Welche GoF Pattern „passen“ zu Scala? Manche Pattern werden „unsichtbar“ durch Scala Sprachmittel ausdrückbar Manche Pattern werden zu Anti-Pattern da man das Ursprungsproblem in Scala anders löst © NovaTec 12.06.2013 5 GoF Pattern – Bewertung für Scala Unsichtbare Pattern Besucher, Brücke, Iterator, Prototyp, Singleton, Strategie Vereinfachte Pattern Abstrakte Fabrik, Beobachter, Dekorierer, Fabrik, Interpreter, Proxy, Zustand, Zuständigkeitskette Anti-Pattern Befehl, Schablonenmethode Sonstige Pattern Adapter, Erbauer, Fassade, Fliegengewicht, Kompositum, Memento, Vermittler Ohne Nachweis im Einzelnen! © NovaTec 12.06.2013 6 Es lohnt sich in Scala nach Quellen neuer Pattern zu suchen © NovaTec 12.06.2013 7 Grundlagen neuer Scala Pattern Jedes neue Scala Feature kann Basis neuer Pattern sein Komplexe Designs kompakter als Pattern beschreibbar (anstelle eines Frameworks) Höherwertige Abstraktionen über der Programmstruktur und Typen erlauben neuartige Compilezeit Pattern Scala läuft auf der JVM aber … Nicht alle Pattern können 1-1 nach Java übersetzt werden Bsp. Cake-Pattern bringt seinen Nutzen zur Compilezeit Nicht übersetzbar: Ausnutzen von Modulstruktur und besserem Typsystem © NovaTec 12.06.2013 8 Scala Blitzkurs © NovaTec 12.06.2013 9 Scala Motivation Scala = Scalable Language Eine Sprache für viele Aufgaben anstelle vieler Sprachen für jeweils eine Aufgabe Skalierung nach Problemgröße Geeignet für kleine Anwendungen (Scripte) • Wichtig: Kompaktheit, Schnelligkeit der Entwicklung, Leicht Anpassbarkeit Geeignet für große Anwendungen • Wichtig: Modularisierung Skalierung nach Komplexität Kontrolle der Komplexität über neue Frameworks, neue Typen und Kontrollstrukturen und eingebettete DSLs © NovaTec 12.06.2013 10 Scala Motivation Forts. Scala kompiliert nach Java Bytecode Nutzt die JVM und alle darauf bestehenden Tools und Frameworks Scala = Java + Viel Gutes aus der Theorie der Programmiersprachen Kompakterer Code (Typ Inferenz, viele Automatismen statt Boilerplate Code) Saubere Integration von Funktionaler Programmierung (Lambda, Closure, Pattern Matching) Traits anstelle von Interfaces Leistungsfähiges Typsystem Modulsystem eingebaut (Trait, Mixin, Abstrakte Member, selftype, Typparameter) Voll Interoperabel mit Java Geschwindigkeit vergleichbar mit Java © NovaTec 12.06.2013 11 Scala Tools scala Repl für interaktive Ausführung Ausführung von Scala Scripten Es gibt wenig was man nicht vollständig in der Repl ausführen kann scalac Kompiliert .scala-Dateien in eine oder mehrere .class-Dateien Scala-Dateien Unterschied zu Java: • Kein Zwang Klasse = Datei • Keine Package-gesteuerte Unterverzeichnisse • Scala-Datei ~ Transcript der Repl – Sequenz von Ausdrücken und Definitionen © NovaTec 12.06.2013 12 Scala Blitzbeispiel - Kompaktheit class MyClass { private int index; private String name; private final int id; } public MyClass(int index, String name) { this.index = index; this.name = name; } // getter und setter für index // getter für name class MyClass(var index: Int, val name: String, id:Int) © NovaTec 12.06.2013 13 Scala Blitzbeispiel - Erweiterbarkeit public BigInteger factorial(BitInteger x) { BigInteger fact; if (x == BigInteger.ZERO) fact = BigInteger.ONE; else fact = x.multiply(factorial(x.subtract(BigInteger.ONE)); return fact; } def factorial(x: BigInt): BigInt = if (x == 0) 1 else x * factorial(x - 1) © NovaTec 12.06.2013 14 Scala – Java Unterschiede Viele kleine Vereinfachungen, z.B. ; am Zeilenende optional Leere Argumentklammern optional Keine Unterscheidung Statement und Ausdruck Implizite Getter und Setter Vereinfachte Konstruktoren Viele Typangaben optional Viele leistungsfähige Verbesserungen -> Grundlage der Scala Pattern object Funktionsobjekte Traits Implicit Konvertierungen Selftype © NovaTec 12.06.2013 15 Scala Packages und Klassen package Beispielklasse { class BoundedPoint(var x:Int, var y:Int) { val maxVal:Int = 32000 if (x.abs > maxVal || y.abs > maxVal) throw new IllegalArgumentException("Point too large") } def this(d:Int) = this(d, d) def mirrored : BoundedPoint = { return new BoundedPoint(y, x) } } © NovaTec 12.06.2013 16 Scala Feature object Definition © NovaTec 12.06.2013 17 Scala Feature - Object Definition Ein object ist die Definition einer Singleton Instanz einer Klasse object MyObject { val constant:Int = 2 var variable:String = "Hello World" def method(param:Int) = variable * param } entspricht etwa class MyObject$ …. val MyObject = new MyObject$() © NovaTec 12.06.2013 18 Object Verwendung Object als Träger von „static“ Variablen und Methoden Scala Terminologie: Ein „Companion Object“ einer Klasse class BoundedPoint…. object BoundedPoint { val unit = new BoundedPoint(0) …. } Object als Modul Ein Package ist ein Object (mit impliziter Definition) Object als Singleton © NovaTec 12.06.2013 19 Singleton Pattern Ein unsichtbares Pattern – object ist ein Singleton Kein Bedarf an getInstance() object Singleton { } var sharedValue = 42 Singleton sharedValue © NovaTec 12.06.2013 20 Factory Pattern - Typsichere Parametrische Factory Nutzt: Pattern Matching, Sealed Klassenhierarchie Leistet: Compilezeit-Prüfung der Factory Parameter sealed abstract class FactoryItem case object Type1 extends FactoryItem case object Type2 extends FactoryItem object Factory { def createItem ( which:FactoryItem) = which match { case Type1 => new Item1() case Type2 => new Item2() } } Factory.createItem(Type2) © NovaTec 12.06.2013 21 Scala Feature Funktionen © NovaTec 12.06.2013 22 Scala Feature - Funktionen Funktionen sind Objekte Können in Variablen gespeichert werden Als Parameter übergeben werden Zur Laufzeit erzeugt werden Literalsyntax: (arg1,… argN) => Ausdruck val nameHasUpperCase = name.exists(char => char.isUpperCase) boolean nameHasUpperCase = false; for (Character char : name) { if (Character.isUpperCase(char)) { nameHasUpperCase = true; break; } } © NovaTec 12.06.2013 23 Scala Feature - First-class Funktionen Funktionen sind Objekte Implementierung: Objekte mit einer Methode apply(parm1, … parmN) Methoden können als Funktionsobjekte extrahiert werden Idiomatische Nutzung: Siehe andere funktionale Programmiersprachen (und den Scala Blog) Ersetzung von (anonymen) Hilfsklassen als Träger von Methoden in Java Pattern Definition von neuen Kontrollstrukturen © NovaTec 12.06.2013 24 Cell Pattern Idiomatisch: Objekte erhalten Funktionscharakter wenn es eine apply Methode gibt Problem: Wir müssen eine Variable per Referenz übergeben Lösung: Wir definieren ein Value-Objekt mit Funktionsverhalten class Cell[T](var value:T) { def apply() = value def update(v:T) = value=v } val cell = new Cell ("") cell() = "Hello World" println(cell()) © NovaTec 12.06.2013 25 Iterator Pattern Iteratoren werden „internalisiert“ und mit dem Iteratorbody parametrisiert Java: List<String> result = new ArrayList<String>; for (String elem: list) { if (elem.indexOf("World") >= 0) result.add(elem) } Scala: list.filter(x:String =>x.contains("World")) Vorteile: Multiple Iteratoren gekapselt in Collections Collection-Typ des Resultats wird durch die Collection bestimmt und nicht durch den Aufrufer © NovaTec 12.06.2013 26 Visitor Pattern Visitor = Iteration über Objektstruktur + Methode für jeden iterierten Elementtyp Scala Lösung #1: Definiere internen Iterator wie bei einer Collection Bsp.: aTree.inorderDo(node:TreeNode => visit Funktionalität) Scala Lösung #2: Rekursion über Objektstruktur mit Pattern-Matching abstract class Expr case class Num(n: Int) extends Expr case class Sum(l: Expr, r: Expr) extends Expr case class Prod(l: Expr, r: Expr) extends Expr def evalExpr(e: Expr): Int = e match { case Num(n) => n case Sum(l, r) => evalExpr(l) + evalExpr(r) case Prod(l, r) => evalExpr(l) * evalExpr(r) } © NovaTec 12.06.2013 27 Observer Pattern Ziel: Benachrichtigung von Observern, wenn das Subject sich ändert Dynamische Registrierung von Observern Scala Idiomatisch: Ersetzen einer Observer Klasse durch eine Funktion case class Event class Subject { private var observers:List[(Event, Subject) => Unit] = Nil def observe(observer: (Event, Subject) => Unit)= observers = observer :: observers def notify(evt:Event) = observers.foreach(_(evt, this)) } subject.observe(e:Event, s:Subject => …..) © NovaTec 12.06.2013 28 Lazy Funktionen Ziel: Konditionaler Aufruf einer teuren Funktion Scala kennt lazy Funktionsparameter Werden ohne Auswertung übergeben Können selber keine Parameter haben if (Trace) System.out.println(expensive()) def trace(f: => Any) { if (Trace) println(f) } trace(expensive()) © NovaTec 12.06.2013 29 Funktionale Pattern – Lazy Lists Lazy Parameter nur ein Beispiel für viele Pattern aus der funktionalen Welt Schwerpunkt 1: Besondere Kontrollstrukturen Stichwort: Continuations Schwerpunkt 2: Infinite Datenstrukturen Scala Streams implementieren potentiell unendliche Listen © NovaTec 12.06.2013 30 Scala Feature Trait © NovaTec 12.06.2013 31 Scala Feature - Traits Traits sind eine Mischung aus abstrakter Klasse und Interface „Interface auf Drogen“ Können Typen, Variablen und abstrakte sowie konkrete Methoden enthalten Traits mischen Verhalten zu Klassen (Mixin) trait NoLogger { def log(level:Int, msg:String) = { } } trait Logger extends NoLogger { val loggerName = this.getClass.getName override def log(level:Int, msg:String) = println("["+level+":"+loggerName+"]" + msg) } class C extends SomeClass with Logger …. © NovaTec 12.06.2013 32 Scala Feature - Traits class MyClass extends SomeClass with Trait1 with Trait2 with Trait3 {…. Traits überschreiben vorhandene Definitionen in der Reihenfolge Rechts nach Links Hat nicht die Problematik mehrfacher Vererbung Trait3 überschreibt Trait2 überschreibt Trait1 überschreibt SomeClass Idiomatisch: Traits dienen der statischen Parametrisierung von konkreten Objekten Siehe das Decorator Pattern Traits dienen der Modularisierung Siehe das Cake Pattern © NovaTec 12.06.2013 33 Decorator Pattern (Stackable Trait) Idiomatisch: Verwendung von Trait Mixins anstelle von Delegation new A with T1 new A with T1 with T2 ergibt "T1 A" ergibt "T2 T1 A" Vorteil: Compilezeit-Operation, gut lesbar, Decorator enthalten nur geänderte Methoden Nachteil: Decorator-Chain nicht dynamisch änderbar class A { } trait T1 { } trait T2 { } © NovaTec override def toString = "A" override def toString = "T1" + super.toString() override def toString = "T2" + super.toString() 12.06.2013 34 Implicit Konvertierung © NovaTec 12.06.2013 35 Scala Feature - Implicit Definitionen Schwieriges Thema und Kandidat für „Gefährlichstes Feature“ in Scala Sehr wichtiges Feature für besonders fortgeschrittene Scala-Pattern Dringende Empfehlung: Nutzung auf festgeschriebene Pattern beschränken! Implizite Definitionen werden automatisch (sofern eindeutig) vom Compiler gesucht und verwendet © NovaTec 12.06.2013 36 Scala Feature - Implicit Definitionen Methoden und Methodenparameter können als implizit gekennzeichnet werden Der Compiler löst Typkonflikte auf, indem er nach passenden impliziten Definitionen sucht Für die folgenden Pattern genügt etwas Intuition Mehr Präzision im Scala Blog Implicit Methoden werden als versteckte Wrapper verwendet Implicit Parameter werden automatisch mit einem implicit Val aufgefüllt Idiomatische Nutzung: Automatische Typkonvertierung (siehe Adapter Pattern) Erweiterung geschlossener Klassen (siehe Pimp My Library Pattern) Statisch aufgelöste Dependency Injection (siehe Type Classes Pattern) © NovaTec 12.06.2013 37 Adapter Pattern Automatische Konvertierung in eine anonyme Adapter-Unterklasse Keine Veränderung an den Originalklassen class Adapter { def someMethod() = ... } class Adaptee { def differentMethod() = ... } val adapter: Adapter = new Adaptee Compiler sucht hier nach impliziter Methode Adaptee=>Adapter implicit def targetAdapteeConv(x:Adaptee):Adapter = new Adapter { override def someMethod() = x. differentMethod()} val adapter: Adapter = targetAdapteeConv(new Adaptee) © NovaTec 12.06.2013 38 Pimp My Library Pattern Problem: Wie erweitere ich eine bestehende API ohne explizite Konvertierungen in Extension-Unterklassen, ohne Wrapper und ohne Casts? Lösung: Eine Variante des Adapter-Pattern auf Methodenebene. Eine anonyme Klasse mit der gewünschten Methode X über dem vorhandenen Typ T Eine implizite Konvertierung von T zur anonymen Klasse für den Aufruf von X Kriterien: Verwende anonyme Klassen weil es idiomatischer ist und nicht den Namensraum zu müllt Beispiel: „3 :: 52“ als Ausdruck für eine Calendar Instanz mit Uhrzeit Dazu müssen wir einen :: Operator der Klasse Integer „unterschieben“ Library Beispiel: ArrayOps Array mit erweiterten Collection-Funktionen © NovaTec 12.06.2013 39 Pimp My Integer 3::52 Compiler sucht nach einer impliziten Konvertierung von Int zu einem Typ mit :: Ergebnis: pimp(52).::(52) implicit def pimp(minutes: Int) = new { def ::(hours:Int) = { var cal = java.util.Calendar.getInstance() cal.set(java.util.Calendar.HOUR_OF_DAY, hours) cal.set(java.util.Calendar.MINUTE, minutes) cal } } Vorteile: Einfache, lokale Erweiterung Leichtgewichtig: wir erzeugen kleine Instanzen mit einer Methode Erweiterung wird durch den Scope kontrolliert © NovaTec 12.06.2013 40 Self Type © NovaTec 12.06.2013 41 Scala Feature - Selftype Selftype ist eine Art Cast von this auf einen gewünschten Zieltyp der konkreten Objekte class MyClass { self: SomeType => …. } MyClass ist dadurch abstrakt (wenn MyClass != SomeType) Konkrete Unterklasse muss alle Definitionen von SomeType enthalten! Idiomatische Nutzung: Constraint auf die Komposition von Klassen aus Traits © NovaTec 12.06.2013 42 Scala Feature - Selftype (Anhand eines Beispiels) trait Hello { def hello = "Hello" } class Test { self: Test with Hello => val helloWorld = hello + "World" } // das ist der Selftype // hello kommt aus Trait Hello new Test error: class Test cannot be instantiated because it does not conform to its self-type Test with Hello val ok = new Test with Hello ok.helloWorld HelloWorld Schlechtere Alternative: class Test extends Hello { val helloWorld = hello + "World"} Warum schlechter? © NovaTec 12.06.2013 43 Cake Pattern Problem: Dekomposition von Code in Module bei kreuzweise Abhängigkeiten der Module Deklarative Komposition des Ergebnis ohne Rückgriff auf Delegation, DI o.ä. Techniken Austauschbare Implementierungen der Module var varModulA:Int def methModulA() = methModulB(valModulB) val valModulB:Int def methModulB(i:Int) = i*varModulA Zwei Codefragmente mit kreuzweiser Abhängigkeit Wie kann man diese unabhängig entwickeln und am Ende zusammenfügen? © NovaTec 12.06.2013 44 Modulare Komposition 1. Versuch trait ModuleA { var varModulA:Int def methModulA() = methModulB(valModulB) } trait ModuleB { } val valModulB:Int def methModulB(i:Int) = i*varModulA Dies ist nicht compilierbar! Java: Explizite Referenz auf benutzte Module, DI und Delegation Scala: Composite selftypes und Mixins © NovaTec 12.06.2013 45 Cake Pattern Cake bildet das modulare Design des Scala Compilers (Komposition verschiedener Module zur Konstruktion des Compiler, der REPL und scaladoc) Konzept: Dekomposition in Traits Scope-Abhängigkeit der Module ermöglicht durch zusammengesetzte selftypes Komposition in einer Klasse Statisch typbar wenn in der Klasse alle Abhängigkeiten aufgelöst sind Als ob alle Traits manuell in ein großes Modul zusammen kopiert wurden Vorteile: Komposition auch bei zyklischen Abhängigkeiten kein Problem Keinerlei Overhead oder erhöhte Komplexität durch die Modularisierung Einfacher Zusammenbau von Implementierungsvarianten © NovaTec 12.06.2013 46 Cake Pattern Skizze trait ModuleA { self:ModuleA with ModuleB => var varModulA:Int def methModulA() = methModulB(valModulB) } trait ModuleB { self:ModuleA with ModuleB => val valModulB:Int def methModulB(i:Int) = i*varModulA } class Composite extends ModuleA with ModuleB { …. } © NovaTec 12.06.2013 47 Type Class Pattern Wichtiges Pattern im Scala 2.8 Collection-Design Problemstellung: Wir müssen verschiedene Klassen mit polymorph nutzbaren Methoden (einer neuen Feature) ausstatten ohne die Klassen zu erweitern. Lösung: Generalisierte Form des Pimp My Library Pattern. Idee: Implementierungen einer Feature für die verschiedenen Klassen Mache diese als implizite neue Klassendefinition verfügbar Methoden die das Feature polymorph nutzen wollen, empfangen dieses durch einen impliziten Methodenparameter Vorteile: Vermeidet Vererbung und Modifikation von Klassen Eine Methode für verschiedene Parametertypen Einfache Benutzung durch implizites DI der benötigten Konzeptimplementierung Reichweitensteuerung über Scoping einfach © NovaTec 12.06.2013 48 Type Class Pattern Beispiel trait InvertableFeature[CType] { def inverse (obj:CType) : CType } implicit val intInvertable = new InvertableFeature[Int] { def inverse (i:Int) = -i } implicit val seqInvertable = new InvertableFeature[Seq] { def inverse (s:Seq) = s.reverse } def inverted[CType](obj:CType)(implicit feature:InvertableFeature[CType]) feature.inversed(obj) = inverted(42) inverted[Int](42)(inInvertable) -42 inverted(1::2::3::Nil) inverted[Seq](1::2::3::Nil)(seqInvertable) List(3,2,1) inverted("HelloWorld") Compiler Fehler © NovaTec 12.06.2013 49 Scala Typen © NovaTec 12.06.2013 50 Scala Feature - Typen Typen können unabhängig von Klassen- oder Interface Definition definiert werden Typen können Member von Klassen, Objecten und Traits sein Typen können als Typparameter (wie in Generics) verwendet werden Typen können zusammengesetzt und verfeinert werden Idiomatische Nutzung von Typen in Pattern Compilezeit Kontrolle Typesafe Builder, Phantom Types Polymorphie Duck Typing © NovaTec 12.06.2013 51 Type Member Beispiel Typen können als Member einer Klasse, Object oder Trait definiert werden class AbstractClass { type T type U <: Seq[T] …. } class RealClass extends AbstractClass { type T = Int …. } Vergleichbar mit Typ-Parameter Warum beide Optionen? Reduktion der Zahl der Typparameter Kapselung der Typ-Parametrisierung © NovaTec 12.06.2013 52 Struktur Typen Notation: { abstrakte Definitionen } Vergleichbar mit einem Ad-Hoc definierten Interface Kern von "Duck Typing" Beschreibt einen Typ eines Objektes anhand des notwendigen Verhaltens type Sizable = { def size: Int } var s:Sizable = "Hello World" s = List(1, 2, 3) © NovaTec 12.06.2013 53 Type Refinement "Verfeinert" einen bestehenden Typ durch weitere Definitionen Typname { DEFINITIONEN } Klassendefinition ist Refinement der Oberklassen und Traits class A extends B { DEFINTIONEN } new A entspricht new B { DEFINITIONEN } Kann explizit als Typ verwendet werden Zur Veränderung eines Variablentyps Zur Veränderung einer neuen Instanz new Dog { def speak() = bark } © NovaTec 12.06.2013 54 Phantom Type Pattern Ziel: Überprüfung des Programmablaufs zur Compilezeit Beispiel: Sicherstellen dass im Builder Pattern eine konsistente Menge von Builder Methoden aufgerufen wurde Lösung: Phantom Types als Zustände eines endlichen Automaten zur Compilezeit Typparameter oder Typ Member halten den aktuellen "Zustand des Automaten" Methodenaufrufe verändern den Zustand über ihren Return-Typ Phantom Type stammt aus Haskel Vereinfacht hier: Ein Typ der nicht in Variablen verwendet wird © NovaTec 12.06.2013 55 Phantom Type Beispiel Skizze case class SocketState[+S <: State]() trait State trait Closed extends State trait Opened extends State Closed und Opened sind Phantom Types trait SocketProcessor { val openSocket: SocketState[Closed] => SocketState[Opened] val readSocket: SocketState[Opened] => SocketState[Opened] val closeSocket: SocketState[Opened] => SocketState[Closed] } val result:SocketState[Closed] = (openSocket readSocket closeSocket)(new SocketState[Closed]) val result:SocketState[Closed] = (openSocket closeSocket readSocket )(new SocketState[Closed]) © NovaTec 12.06.2013 56 Typesafe Builder Pattern (Phantom Type) Typsichere Pizza Bäckerei Phantom Type beschreibt Zustand der Pizza Implizit Konvertierung zur Prüfung des korrekten Endzustands © NovaTec 12.06.2013 57 Duck Typing Duck Typing wurde in Anlehnung an ein Gedicht von James Whitcomb Rileys benannt. In der Kurzform: If it walks like a duck and quacks like a duck, it is a duck. Ziel: Polymorphe Nutzung von Objekten aus unabhängigen Klassenhierarchien Verschiedenste Objekte sollen austauschbar sein Unabhängig von ihrer Klassenhierarchie Sie müssen nur die benötigten Methoden implementieren Polymorphie von Smalltalk und Ruby Strategie: Structural Type zur Definition der erforderten Methoden Pimp my Library zur Anpassung existierenden geschlossener Klassen Live Beispiel © NovaTec 12.06.2013 58 Noch nicht müde? scala.novatec-gmbh.de Vielen Dank! © NovaTec 12.06.2013 59 Scala Klassenhierarchie © NovaTec 12.06.2013 60 Exkurs: Typausdrücke für Instanzen new A with T1 with T2 Com pound Typ new A { def toString = "Anonymes A" } Refinem ent var duck:{ def toString:String } = new A Struk turtyp (Duck Typing) Idiomatisch: Sehr häufige Verwendung von Typausdrücken anstelle von Klassendefinitionen • Führen intern zu Java anonymen Klassen Reduktion der Zahl der konkreten Klassendefinitionen im Vergleich zu Java Expliziter Ausdruck der Kompositions-Struktur einer Instanz © NovaTec 12.06.2013 61