[1]

                                         Scala




                                                 Scala


present D...
2



  Grande
  Cinnamon Dolce
  Latte with tripple
  shot with non-fat
  milk topped with
  whipped cream
[2]
3



                                          [3]
place orders (
 new Order to buy(100 sharesOf ”IBM”)
   limitPrice 300
...
4
Agenda


           Was sind       Warum
            DSLs          Scala?


         DSL Beispiele
                     ...
[4]




Was sind DSLs?
6
DSL
Allgemeine Definition

˃ Domain Specific Language
    • Oder auch Fluent API
˃ Domain – [Domäne]
    • Problemorient...
7
Domäne
… oder auch Anwendungsdomäne

˃ Sammlung an Abläufen, Objekten und
  Rahmenbedingungen die Teil der Fachdomäne
  ...
8
Ausdrucksschwäche von GPLs
Ocean ocean = new Ocean ();
Fish fish1 = new Fish ();
fish1.setSize(Size.TINY);
fish1.setColo...
9
Ausdrucksschwäche von GPLs
Ocean ocean = new Ocean ();        Wenn man eigentlich meint…
Fish fish1 = new Fish ();
     ...
10
Ausdrucksschwäche von GPLs
Ocean ocean = new Ocean ();        Mit Scala 2.8: Named Parameters
Fish fish1 = new Fish ();...
11



                           [5]




Klassifizierung von DSLs
12
Klassifizierung

˃ Es gibt zwei wesentliche Unterschiede bei DSLs
   • Interne DSLs
   • Externe DSLs


˃ Es gibt aller...
13
Interne DSLs

˃ Eingebettet in eine Host-Sprache
   • z. B. in Java, Groovy, Scala, Python, C# …
˃ Beeinflusst und limi...
14
Externe DSLs

˃ Liegen meist in Form von Skripten oder
  interpretierbaren Text-Dateien vor
   • Graphviz, (X)HTML
˃ We...
15
Graphische DSLs

˃ Graphische Modellierung einer Domäne
   • UML, BPM
˃ Meist verbunden mit einem spezifischen Tool
   ...
16



                  [6]




Stand der Dinge
17
Naive API
… ohne wirkliches Design

Cream c = new WhippedCream ();
Coffee coffee = new              [7]
Coffee(”Cinnamo...
18
Query API
… am Starbucks Beispiel

Coffee coffee = new Coffee();
coffee.setSize(Size.Grande);
coffee.setType(Type.Cinna...
19
Query API
… am Starbucks Beispiel

Coffee coffee = new Coffee();
coffee.setSize(Size.Grande);
coffee.setType(Type.Cinna...
[8]




Builder-Pattern
21
Das Builder-Pattern
… Expression-Builder
˃ Grundlage
   • Mittels Method-Chaining Lesbarkeit von Query APIs
     erhöhe...
22
Allgemeine Umsetzung
… In Java

    Object o = new Object.Builder(General)
                       .configureA (A)
     ...
23
Fluent-APIs (mit dem Builder-Pattern)
… am Starbucks Beispiel

Coffee coffee = new Coffee.Builder
(Size.Grande, Type.Ci...
24
Fluent-APIs (mit dem Builder-Pattern)
… am Starbucks Beispiel

Coffee coffee = new Coffee.Builder
(Size.Grande, Type.Ci...
25

Code is written for people
    … and only then for computers!




                 [11]
26




                 [12]




Ziele für DSLs
27
Ziele
Im Vordergrund

˃ Klare Wiedergabe der Absicht eines Systems
   • Im Bezug auf die Domäne
˃ Einfachere Lesbarkeit...
28
Ziele
… langfristig

 ˃ Abstraktionsebene von Software erhöhen
 ˃ Software-Entwicklung erleichtern
 ˃ Zeit einsparen
  ...
29
Ziele
… langfristig

 ˃ Abstraktionsebene von Software erhöhen
 ˃ Software-Entwicklung erleichtern
 ˃ Zeit einsparen
  ...
30
Schwierigkeiten
… bei der Umsetzung

˃ Korrekte Abbildung einer Domäne in einer
  gegebenen Sprache oftmals schwierig
˃...
31
Roadmap für den Einsatz von DSLs
… am Beispiel Scala
˃ Schritt 1
    • Tests von Java Objekten mit Scala DSL
˃ Schritt ...
32




               [13]




Warum Scala?
33
Warum Scala
… einsetzen für Domain Specific Languages?

˃ Weniger „Noise“
   •   Optionale Punkte beim Methodenaufruf
 ...
34
„Fluent“-ness von Scala
Ohne
val s : Int = new Palm().get (new
Banana(3)).size;
35
„Fluent“-ness von Scala
mit Companion-Object und Type-Inference
val s : Int = new Palm().get (new
Banana(3)).size;

val...
36
„Fluent“-ness von Scala
mit Punkt- und Semicolon-Inferenz
val s : Int = new Palm().get (new
Banana(3)).size;

val s = P...
[14]




CLOSURES & FUNCTIONS
38
CLOSURES & FUNCTIONS
Closures

˃ Anonyme Funktionen
˃ Verwendung von Variablen aus dem aktuellen
  Scope möglich

     ...
39
CLOSURES & FUNCTIONS
Currying (1/2)




     def uncurried(s:String, i:Int):String = {
          s + i
     }

     pri...
40
CLOSURES & FUNCTIONS
Currying (2/2)

           def curried(s:String)(i:Int):String = {
                s + " " + i
   ...
41
CLOSURES & FUNCTIONS
Implicit Conversions                        Best Practice

                                       ...
[15]




CASE CLASSES
43
CASE CLASSES
Idee

˃ Normale Klassen mit Modifier case
˃ Erhalten implizit erweiterte Funktionen
   • Verwendbarkeit in...
44
CASE CLASSES
Definition und Verwendung

    abstract class TrainWaggon

    case class StandardWaggon(seats : Int)
    ...
45
CASE CLASSES
Beispiel „Option“


 val result : Option[String] = ... // Ergebnis einer
                                 ...
[17]




PATTERN MATCHING
47
PATTERN MATCHING
Matching auf Werte



  val input : String = "..." // Aus Eingaben, Dateien, ...

  val choice   = inp...
48
PATTERN MATCHING
Matching mit Objekten

˃ Case Classes optimal verwendbar
˃ Elegante Steuerung des Kontrollflusses
  va...
[18]




PARTIAL FUNCTIONS
50
PARTIAL FUNCTIONS

    val match1 : PartialFunction[String, String] = {
          case "pictures" => displayPictureGall...
[19]




PARSER COMBINATORS
52
PARSER COMBINATORS [MAGIC]
object SimpleScala extends RegexpParsers {

  val ID = """[a-zA-Z]([a-zA-Z0-9]|_[a-zA-Z0-9])...
[20]




Beispiele für DSLs in Scala
[21]




Finance DSL in Scala
55
Finance DSL in Scala
aus DSLsinAction


 val fixedIncomeTrade =
             200.discount_bonds(IBM)
                  ...
56
Finance DSL in Scala
aus DSLsinAction


 val fixedIncomeTrade =
             200 discount_bonds IBM
                   ...
[22]




Starbucks DSL in Scala
58
Starbucks Scala DSL
Beispiel für die Verwendung

val o = order (
    Tall (CinnamonDolceLatte decaf
    None withMilk N...
59
Starbucks Scala DSL
Schade ist…

val o = order (
    Tall (CinnamonDolceLatte decaf
    None withMilk NonFat withCream
...
60
Starbucks Scala DSL
Verwendete Konzepte

˃ Companion + apply () für order (…)
˃ Case Objects um „new“ zu entgehen
   • ...
[23]




ScalaTest DSL
62
ScalaTest DSL
http://www.scalatest.org
class StackSpec extends FlatSpec with ShouldMatchers {

  "A Stack" should "pop ...
63
Und mehr
… weitere Scala DSLs

˃ ScalaModules [SCALAMODULES]
    • Konfiguration von OSGi Bundles
˃ Squeryl [SQUERYL]
 ...
[24]




DB4O


       [LOGOS]
65
DB4O
Native Queries

˃ Interfaces: Predicate<T>, Comparator<T>

   final ObjectSet<User> nativeQuery = database.query(n...
66
DB4O [SCADB4O] [SCADB4O2]
Offensichtliche Vereinfachung für Native Queries
  final ObjectSet<User> nativeQuery = databa...
67
DB4O
SODA Queries

˃ Builder-Pattern
   final Query query = database.query();

   query.constrain(User.class);

   quer...
68
DB4O
Komplexere DSL für SODA Queries (1/8)



                        Idee

    DB4O Abfragen SQL-ähnlich modellieren!
69
DB4O
Komplexere DSL für SODA Queries (2/8)




db select User.getClass where(„name := “Bart“) and('age < 20)
70
 DB4O
 Komplexere DSL für SODA Queries (3/8)

          ObjectContainer



 db select User.getClass where(„name := “Bar...
71
DB4O
Komplexere DSL für SODA Queries (4/8)




db select User.getClass where(„name := “Bart“) and('age < 20)



case cl...
72
DB4O
Komplexere DSL für SODA Queries (5/8)
                          def :=(obj:Any):DSLConstraint={…}


              ...
73
DB4O
Komplexere DSL für SODA Queries (6/8)


                   abstract class Operator
„name := “Bart“    case object ...
74
DB4O
Komplexere DSL für SODA Queries (7/8)
val res = c.operator match {


case EQUALS => q.descend(c.symbol.name)
     ...
75
DB4O
Komplexere DSL für SODA Queries (8/8)

 ˃ Verwendete Scala Features
    •   Implicit Conversions
    •   Builder P...
[25]




THE DAWN OF DSLs
                   [LOGOS]
77




       [26]




DEMO
SOURCECODE

http://github.com/jwachter/scala-db4o-dsl
79




               [27]




NOCH FRAGEN?
80
Werbung




     http://scala-southerngermany.mixxt.de/
81
Quellen

[BAYSICK]
http://blog.fogus.me/2009/03/26/baysick-a-scala-dsl-implementing-basic/
[STIME]
http://github.com/jo...
82
Quellen
Bilder (1/3)
 [1] XKCD, http://xkcd.com/353/
 [2] http://www.flickr.com/photos/stephenccwu/3035854901/
 [3] htt...
83
Quellen
Bilder (2/3)
 [15] http://www.flickr.com/photos/zkorb/1592677291/
 [17] http://www.flickr.com/photos/mortimer/2...
84
Quellen
Bilder(3/3)
 [LOGOS]
 DB4O - http://www.db4o.com
 LIFT - http://www.liftweb.net
 WEBDSL - http://www.webdsl.org...
85
License
Präsentation




            http://creativecommons.org/licenses/by-nc-nd/3.0/de/


Quelltext



              ...
Nächste SlideShare
Wird geladen in …5
×

DSLs in Scala & DB4O

2.155 Aufrufe

Veröffentlicht am

A presentation about DSLs in general, what Scala has to offer in terms of internal DSLs and finally a custom DSL example that uses the DB4O database.

Veröffentlicht in: Technologie, Business
0 Kommentare
1 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
2.155
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
53
Aktionen
Geteilt
0
Downloads
30
Kommentare
0
Gefällt mir
1
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

DSLs in Scala & DB4O

  1. 1. [1] Scala Scala present DSLs in Scala for MSI at HSMA Marcus Körner (@atla_) Johannes Wachter (@jow85)
  2. 2. 2 Grande Cinnamon Dolce Latte with tripple shot with non-fat milk topped with whipped cream [2]
  3. 3. 3 [3] place orders ( new Order to buy(100 sharesOf ”IBM”) limitPrice 300 allOrNone using premiumPricing, new Order to sell(200 bondsOf ”CISCO”) limitPrice 300 allOrNone using { (qty, unit) => qty * unit - 500 } ) Beispiel aus [DSLSINACTION]
  4. 4. 4 Agenda Was sind Warum DSLs Scala? DSL Beispiele DB4O DSL in Scala
  5. 5. [4] Was sind DSLs?
  6. 6. 6 DSL Allgemeine Definition ˃ Domain Specific Language • Oder auch Fluent API ˃ Domain – [Domäne] • Problemorientiert • „Fachsprache“ ˃ Specific – [Speziell] • Konkret entworfen für einen spezifischen Einsatzzweck • Abgrenzung zur General Purpose Language
  7. 7. 7 Domäne … oder auch Anwendungsdomäne ˃ Sammlung an Abläufen, Objekten und Rahmenbedingungen die Teil der Fachdomäne sind ˃ Brücke zwischen realen Objekten aus der Welt des Anwenders und Objekten eines Softwaresystems ˃ Domain-Driven-Design • Schwerpunkt ist die Fachlichkeit und Fachlogik • Ideales Einsatzgebiet für DSLs!
  8. 8. 8 Ausdrucksschwäche von GPLs Ocean ocean = new Ocean (); Fish fish1 = new Fish (); fish1.setSize(Size.TINY); fish1.setColor(Color.RED); Fish fish2 = new Fish (); fish2.setSize(Size.MIDSIZE); fish2.setColor(Color.BLUE); Shark shark = new Shark (); shark.setSize(Size.HUGE); shark.setColor(Color.WHITE); Jellyfish jellyfish = new Jellyfish (); jellyfish.setSize(Size.SMALL); Turtle turtle = new Turtle (); turtle.setSize (Size.SMALL); ocean.add (fish1); ocean.add (fish2); ocean.add (shark); ocean.add (jellyfish); ocean.add (turtle);
  9. 9. 9 Ausdrucksschwäche von GPLs Ocean ocean = new Ocean (); Wenn man eigentlich meint… Fish fish1 = new Fish (); ocean ( fish1.setSize(Size.TINY); ? fish1.setColor(Color.RED); Fish fish2 = new Fish (); fish2.setSize(Size.MIDSIZE); fish (TINY, RED), fish (SMALL, BLUE), shark (HUGE, WHITE), ? fish2.setColor(Color.BLUE); jellyfish (SMALL), Shark shark = new Shark (); turtle (SMALL) shark.setSize(Size.HUGE); ) shark.setColor(Color.WHITE); ? Jellyfish jellyfish = new Jellyfish (); jellyfish.setSize(Size.SMALL); Turtle turtle = new Turtle (); turtle.setSize (Size.SMALL); ? ocean.add (fish1); ocean.add (fish2); ocean.add (shark); ocean.add (jellyfish); ocean.add (turtle);
  10. 10. 10 Ausdrucksschwäche von GPLs Ocean ocean = new Ocean (); Mit Scala 2.8: Named Parameters Fish fish1 = new Fish (); ocean ( fish1.setSize(Size.TINY); ? fish1.setColor(Color.RED); Fish fish2 = new Fish (); fish2.setSize(Size.MIDSIZE); ) fish (size=TINY, color=RED), jellyfish (size=SMALL) ? fish2.setColor(Color.BLUE); Shark shark = new Shark (); shark.setSize(Size.HUGE); shark.setColor(Color.WHITE); ? Jellyfish jellyfish = new Jellyfish (); jellyfish.setSize(Size.SMALL); Turtle turtle = new Turtle (); turtle.setSize (Size.SMALL); ? ocean.add (fish1); ocean.add (fish2); ocean.add (shark); ocean.add (jellyfish); ocean.add (turtle);
  11. 11. 11 [5] Klassifizierung von DSLs
  12. 12. 12 Klassifizierung ˃ Es gibt zwei wesentliche Unterschiede bei DSLs • Interne DSLs • Externe DSLs ˃ Es gibt allerdings auch einige graphische DSLs
  13. 13. 13 Interne DSLs ˃ Eingebettet in eine Host-Sprache • z. B. in Java, Groovy, Scala, Python, C# … ˃ Beeinflusst und limitiert von den Sprachmitteln der Host-Sprache ˃ Einige Vertreter • LINQ (C#), Grails (Groovy), Lift (Scala), WebDSL (Scala)
  14. 14. 14 Externe DSLs ˃ Liegen meist in Form von Skripten oder interpretierbaren Text-Dateien vor • Graphviz, (X)HTML ˃ Werden entweder • interpretiert • compiliert in eine andere Sprache (Xtext) ˃ Kennen wir alle nur zu gut… • SQL, Ant-Skripte, Makefiles, XML Konfigurationen
  15. 15. 15 Graphische DSLs ˃ Graphische Modellierung einer Domäne • UML, BPM ˃ Meist verbunden mit einem spezifischen Tool • Bsp. Microsoft Oslo, JetBrains MPS, Intentional Domain Workbench ˃ Gut geeignet zum Dokumentieren ˃ Schlecht geeignet zum eigentlichen Entwickeln!
  16. 16. 16 [6] Stand der Dinge
  17. 17. 17 Naive API … ohne wirkliches Design Cream c = new WhippedCream (); Coffee coffee = new [7] Coffee(”CinnamonDolce”, TYPE_LATTE); coffee.sized(4); coffee.setDecaf (”decaf none”); coffee.addCream(c);
  18. 18. 18 Query API … am Starbucks Beispiel Coffee coffee = new Coffee(); coffee.setSize(Size.Grande); coffee.setType(Type.CinnamonDolceLatte); coffee.setDecaf(DecafLimit.Full); coffee.setMilk(Milk.NonFat); coffee.setCream(Cream.WhippedCream);
  19. 19. 19 Query API … am Starbucks Beispiel Coffee coffee = new Coffee(); coffee.setSize(Size.Grande); coffee.setType(Type.CinnamonDolceLatte); coffee.setDecaf(DecafLimit.Full); coffee.setMilk(Milk.NonFat); coffee.setCream(Cream.WhippedCream); ˃ Das geht doch schöner, oder?
  20. 20. [8] Builder-Pattern
  21. 21. 21 Das Builder-Pattern … Expression-Builder ˃ Grundlage • Mittels Method-Chaining Lesbarkeit von Query APIs erhöhen ˃ Umsetzung • Ein oder mehrere Objekte die ein Fluent Interface anbieten und in eine darunterliegende Query-API transformieren. ˃ Ziel • Soll ähnlich lesbar wie eine interne DSL sein • Gutes Design für moderne APIs: Builder für die wichtigsten Objekte
  22. 22. 22 Allgemeine Umsetzung … In Java Object o = new Object.Builder(General) .configureA (A) .configureB (B) .configureC (C) .build (); [9]
  23. 23. 23 Fluent-APIs (mit dem Builder-Pattern) … am Starbucks Beispiel Coffee coffee = new Coffee.Builder (Size.Grande, Type.CinnamonDolceLatte) [10] .with (DecafLimit.Half) .with (Milk.Soy) .with (Cream.WhippedCream) .build();
  24. 24. 24 Fluent-APIs (mit dem Builder-Pattern) … am Starbucks Beispiel Coffee coffee = new Coffee.Builder (Size.Grande, Type.CinnamonDolceLatte) [10] .with (DecafLimit.Half) .with (Milk.Soy) .with (Cream.WhippedCream) .build(); ˃ Nicht schlecht, aber warum soviel Overhead?
  25. 25. 25 Code is written for people … and only then for computers! [11]
  26. 26. 26 [12] Ziele für DSLs
  27. 27. 27 Ziele Im Vordergrund ˃ Klare Wiedergabe der Absicht eines Systems • Im Bezug auf die Domäne ˃ Einfachere Lesbarkeit • flüssig • Hin zu natürlicher Sprache ˃ Bessere Modellierung der Domäne ˃ Domänenexperten sollten DSL verstehen und lesen können • Nicht zwingend selbst damit arbeiten (Wunschdenken)
  28. 28. 28 Ziele … langfristig ˃ Abstraktionsebene von Software erhöhen ˃ Software-Entwicklung erleichtern ˃ Zeit einsparen • Bei der Kommunikation mit Domänen-Experten • Beim Umsetzen von fachlichen Anforderungen
  29. 29. 29 Ziele … langfristig ˃ Abstraktionsebene von Software erhöhen ˃ Software-Entwicklung erleichtern ˃ Zeit einsparen • Bei der Kommunikation mit Domänen-Experten • Beim Umsetzen von fachlichen Anforderungen ˃ Und nein, Entwickler wollen wir nicht abschaffen • Hat bei COBOL auch nicht geklappt ;)
  30. 30. 30 Schwierigkeiten … bei der Umsetzung ˃ Korrekte Abbildung einer Domäne in einer gegebenen Sprache oftmals schwierig ˃ Anpassung an die Host-Sprache notwendig ˃ DSL fühlt sich „fremd“ an in der Host-Sprache ˃ Warum passt sich die Sprache nicht der Domäne an?
  31. 31. 31 Roadmap für den Einsatz von DSLs … am Beispiel Scala ˃ Schritt 1 • Tests von Java Objekten mit Scala DSL ˃ Schritt 2 • Scala DSL als Smart-Wrapper um Java Objekte herum ˃ Schritt 3 • Nicht-kritische Funktionalität mit Hilfe einer Scala DSL modellieren ˃ Man muss nicht gleich Produktionscode auf Scala umstellen…
  32. 32. 32 [13] Warum Scala?
  33. 33. 33 Warum Scala … einsetzen für Domain Specific Languages? ˃ Weniger „Noise“ • Optionale Punkte beim Methodenaufruf • Semikolon-Inferenz • Typ-Inferenz • Operatoren als Methoden und Infix-Operatoren • Optionale Klammern (an manchen Stellen) ˃ Funktionale Aspekte • Gleich mehr dazu ˃ Combinator Parsing (für externe DSLs)
  34. 34. 34 „Fluent“-ness von Scala Ohne val s : Int = new Palm().get (new Banana(3)).size;
  35. 35. 35 „Fluent“-ness von Scala mit Companion-Object und Type-Inference val s : Int = new Palm().get (new Banana(3)).size; val s = Palm().get (Banana(3)).size;
  36. 36. 36 „Fluent“-ness von Scala mit Punkt- und Semicolon-Inferenz val s : Int = new Palm().get (new Banana(3)).size; val s = Palm().get (Banana(3)).size; val s = Palm() get (Banana(3)) size
  37. 37. [14] CLOSURES & FUNCTIONS
  38. 38. 38 CLOSURES & FUNCTIONS Closures ˃ Anonyme Funktionen ˃ Verwendung von Variablen aus dem aktuellen Scope möglich val greeting = "Welcome" val greet : String => String = s => { greeting + " " + s } println greet("MSI Course") // Welcome MSI Course
  39. 39. 39 CLOSURES & FUNCTIONS Currying (1/2) def uncurried(s:String, i:Int):String = { s + i } println(uncurried("foo -> ", 1)) // foo -> 1
  40. 40. 40 CLOSURES & FUNCTIONS Currying (2/2) def curried(s:String)(i:Int):String = { s + " " + i } val prefill = curried("foo") _ Currying ermöglicht val execute = prefill(1) - Partially Applied Functions println(execute) // foo 1 - „Neue“ Kontrollstrukturen val control = curried("foo"){ 1 + 10 - 12 } println(control) // foo -1
  41. 41. 41 CLOSURES & FUNCTIONS Implicit Conversions Best Practice Implicit Conversions in ˃ „Magische Konvertierung“ Singleton Objects kapseln. ˃ Vorhandene APIs erweitern import some.Object.* class EnhancedInt(val int:Int){ def toBinaryString():String = { // ... } } implicit def intToEnhancedInt(i:Int):EnhancedInt={ new EnhancedInt(i) } println(12 toBinaryString) // 1100
  42. 42. [15] CASE CLASSES
  43. 43. 43 CASE CLASSES Idee ˃ Normale Klassen mit Modifier case ˃ Erhalten implizit erweiterte Funktionen • Verwendbarkeit in Pattern Matching • Implizites Companion Object • Automatische Vergleichbarkeit
  44. 44. 44 CASE CLASSES Definition und Verwendung abstract class TrainWaggon case class StandardWaggon(seats : Int) extends TrainWaggon case class BistroWaggon(seats : Int, bar : Boolean) extends TrainWaggon case class BaggageWaggon(capacity : Int) extends TrainWaggon StandardWaggon(50) BistroWaggon(20, true) BaggageWaggon(200)
  45. 45. 45 CASE CLASSES Beispiel „Option“ val result : Option[String] = ... // Ergebnis einer anderen Funktion Some("Inhalt") // Es wurde ein Ergebnis erstellt und zurückgeliefert None // Es wurde kein Ergebnis erstellt
  46. 46. [17] PATTERN MATCHING
  47. 47. 47 PATTERN MATCHING Matching auf Werte val input : String = "..." // Aus Eingaben, Dateien, ... val choice = input match { case "xml" => exportToXML case "json" => exportToJSON case "doc" => exportToWord case "docx" if isDocxEnabled => exportToWord case _ => invalidExport // Weitere Eingabenwerte }
  48. 48. 48 PATTERN MATCHING Matching mit Objekten ˃ Case Classes optimal verwendbar ˃ Elegante Steuerung des Kontrollflusses val input : Option[String] = ... // Some("test"), None input match { case Some("foobar") => false case Some("test") => true case None => false }
  49. 49. [18] PARTIAL FUNCTIONS
  50. 50. 50 PARTIAL FUNCTIONS val match1 : PartialFunction[String, String] = { case "pictures" => displayPictureGallery case "about" => displayAboutInformation } val match2 : PartialFunction[String, String] = { case "users" => displayUserList case "news" => displayNews } match1("users") match1 isDefinedAt "users" // scala.MatchError // false match2("users") match2 isDefinedAt "users„ // führt displayUserList aus // true
  51. 51. [19] PARSER COMBINATORS
  52. 52. 52 PARSER COMBINATORS [MAGIC] object SimpleScala extends RegexpParsers { val ID = """[a-zA-Z]([a-zA-Z0-9]|_[a-zA-Z0-9])*"""r val NUM = """[1-9][0-9]*"""r def program = clazz* // ... def classPrefix = "class" ~ ID ~ "(" ~ formals ~ ")" // ... Parser direkt in Scala anhand einer DSL def expr: Parser[Expr] = factor ~ ( definieren. "+" ~ factor | "-" ~ factor Beispiele: )* - JSON - SimpleScala // ... - WebDSL
  53. 53. [20] Beispiele für DSLs in Scala
  54. 54. [21] Finance DSL in Scala
  55. 55. 55 Finance DSL in Scala aus DSLsinAction val fixedIncomeTrade = 200.discount_bonds(IBM) .for_client(NOMURA) .on(NYSE) .at(72.ccy(USD)) Beispiel aus [DSLSINACTION]
  56. 56. 56 Finance DSL in Scala aus DSLsinAction val fixedIncomeTrade = 200 discount_bonds IBM for_client NOMURA on NYSE at 72.ccy(USD) Beispiel aus [DSLSINACTION]
  57. 57. [22] Starbucks DSL in Scala
  58. 58. 58 Starbucks Scala DSL Beispiel für die Verwendung val o = order ( Tall (CinnamonDolceLatte decaf None withMilk NonFat withCream WhippedCream), Grande (ConPanna decaf Half), Venti (FlavoredLatte decaf None withMilk Soy withCream NoWhippedCream) )
  59. 59. 59 Starbucks Scala DSL Schade ist… val o = order ( Tall (CinnamonDolceLatte decaf None withMilk NonFat withCream WhippedCream), Grande (ConPanna decaf Half), Venti (FlavoredLatte decaf None withMilk Soy withCream NoWhippedCream) )
  60. 60. 60 Starbucks Scala DSL Verwendete Konzepte ˃ Companion + apply () für order (…) ˃ Case Objects um „new“ zu entgehen • Kaffeesorten (CinnamonDolceLatte, ConPanna…) • Milchsorten (NonFat, Soy…) • Größen (Tall, Venti, Grande…)
  61. 61. [23] ScalaTest DSL
  62. 62. 62 ScalaTest DSL http://www.scalatest.org class StackSpec extends FlatSpec with ShouldMatchers { "A Stack" should "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) stack.pop() should equal (2) stack.pop() should equal (1) } it should "throw NoSuchElementException if an empty stack is popped" in { val emptyStack = new Stack[String] evaluating { emptyStack.pop() } should produce [NoSuchElementException] } } Beispiel von [SCALATEST]
  63. 63. 63 Und mehr … weitere Scala DSLs ˃ ScalaModules [SCALAMODULES] • Konfiguration von OSGi Bundles ˃ Squeryl [SQUERYL] • Scala ORM und DSL für SQL-Datenbanken ˃ Baysick [BAYSICK] • Scala DSL die BASIC implementiert ˃ Apache Camel DSL [CAMELDSL] • DSL zur Integration von ESB Komponenten
  64. 64. [24] DB4O [LOGOS]
  65. 65. 65 DB4O Native Queries ˃ Interfaces: Predicate<T>, Comparator<T> final ObjectSet<User> nativeQuery = database.query(new Predicate<User>() { @Override public boolean match(final User o) { final User user = o; return user.getLastName().equals("Flanders") && user.getFirstName().endsWith("od"); } });
  66. 66. 66 DB4O [SCADB4O] [SCADB4O2] Offensichtliche Vereinfachung für Native Queries final ObjectSet<User> nativeQuery = database.query(new Predicate<User>() { … }); ˃ Anonyme Klasse ersetzen durch Closure ˃ Transformation mit Implicit Conversions db query { user : User => user.name.contains("t") } implicit def toPredicate[T](predicate: T => Boolean) = { new Predicate[T]() { def `match`(entry: T): Boolean = { predicate(entry) Durch fehlende } Kompatibilität mit } Query Optimizer nicht } „Production ready“
  67. 67. 67 DB4O SODA Queries ˃ Builder-Pattern final Query query = database.query(); query.constrain(User.class); query.descend("firstName").constrain("Johannes"); query.descend("lastName").constrain("Wachter"); query.descend("birthday").constrain("1985").like(); query.descend("age").constrain("19").smaller(); final ObjectSet<User> execute = query.execute();
  68. 68. 68 DB4O Komplexere DSL für SODA Queries (1/8) Idee DB4O Abfragen SQL-ähnlich modellieren!
  69. 69. 69 DB4O Komplexere DSL für SODA Queries (2/8) db select User.getClass where(„name := “Bart“) and('age < 20)
  70. 70. 70 DB4O Komplexere DSL für SODA Queries (3/8) ObjectContainer db select User.getClass where(„name := “Bart“) and('age < 20) implicit def oCToDSLOC(c : ObjectContainer):DSLObjectContainer = DSLObjectContainer(c) case class DSLObjectContainer(val c : ObjectContainer){…}
  71. 71. 71 DB4O Komplexere DSL für SODA Queries (4/8) db select User.getClass where(„name := “Bart“) and('age < 20) case class DSLQuery[T](query : Query, clazz : Class[T]) extends QueryUtil{ def where(constr : DSLConstraint):ExtendedDSLQuery[T]={…} def order(order : DSLOrdering):DSLQuery[T]{…} def execute()={…} }
  72. 72. 72 DB4O Komplexere DSL für SODA Queries (5/8) def :=(obj:Any):DSLConstraint={…} Symbol db select User.getClass where(„name := “Bart“) and('age < 20) implicit def sToConstr(s: Symbol):DSLConstraint={ DSLConstraint(symbol) }
  73. 73. 73 DB4O Komplexere DSL für SODA Queries (6/8) abstract class Operator „name := “Bart“ case object SMALLER extends Operator case object SMALLER_EQUAL extends Operator case class DSLConstraint(s : Symbol, var b : Any = 0, var op : Operator = EQUALS){ def :=(obj:Any):DSLConstraint={…} def ~|(obj:String):DSLConstraint={…} }
  74. 74. 74 DB4O Komplexere DSL für SODA Queries (7/8) val res = c.operator match { case EQUALS => q.descend(c.symbol.name) .constrain(c.bound).equal case SMALLER => q.descend(c.symbol.name) .constrain(c.bound).smaller case SMALLER_EQUAL => q.descend(c.symbol.name).constrain(c.bound).smaller() .or(q.descend(c.symbol.name).constrain(c.bound).equal) } def or(c : DSLConstraint):ExtendedDSLQuery[T]={ q.constraints().or(constrain(q, c)) this }
  75. 75. 75 DB4O Komplexere DSL für SODA Queries (8/8) ˃ Verwendete Scala Features • Implicit Conversions • Builder Pattern • Case Objects • Pattern Matching ˃ Typisches Beispiel: Wrapper für Bibliothek ˃ Viele Möglichkeiten APIs „lesbar“ abzubilden
  76. 76. [25] THE DAWN OF DSLs [LOGOS]
  77. 77. 77 [26] DEMO
  78. 78. SOURCECODE http://github.com/jwachter/scala-db4o-dsl
  79. 79. 79 [27] NOCH FRAGEN?
  80. 80. 80 Werbung http://scala-southerngermany.mixxt.de/
  81. 81. 81 Quellen [BAYSICK] http://blog.fogus.me/2009/03/26/baysick-a-scala-dsl-implementing-basic/ [STIME] http://github.com/jorgeortiz85/scala-time [SCADB4O] http://matlik.net/blog/2007/11/28/scala-and-db4o-native-queries/ [SCADB4O2] http://www.matthewtodd.info/?p=68 [SQUERYL] http://squeryl.org/ [SCALATEST] http://www.scalatest.org [DSLSINACTION] Debashish Ghosh – DSLs In Action (MEAP) (http://manning.com/ghosh/) [MAGIC] Daniel Spiewak, http://www.codecommit.com/blog/scala/the-magic-behind-parser-combinators [FOWLER] Martin Fowler, http://martinfowler.com/dslwip (News zum Buch unter http://martinfowler.com/snips/201005261418.html) [SCALAMODULES] http://wiki.github.com/weiglewilczek/scalamodules/ [CAMELDSL] http://camel.apache.org/scala-dsl.html
  82. 82. 82 Quellen Bilder (1/3) [1] XKCD, http://xkcd.com/353/ [2] http://www.flickr.com/photos/stephenccwu/3035854901/ [3] http://www.flickr.com/photos/travel_aficionado/2396814840/ [4] http://www.flickr.com/photos/leonardlow/340763653/ [5] http://www.flickr.com/photos/13698839@N00/3001363490/ [6] http://www.flickr.com/photos/spherical_perceptions/4634722058/ [7] http://www.flickr.com/photos/7202153@N03/4623364964/ [8] http://www.flickr.com/photos/v1ctory_1s_m1ne/3416173688/ [9] http://www.flickr.com/photos/gorbould/3083371867/ [10] http://www.flickr.com/photos/jpdaigle/4221047282/ [11] http://www.flickr.com/photos/trinity-of-one/20562069/ [12] http://www.flickr.com/photos/bogdansuditu/2377844553/ [13] http://www.flickr.com/photos/stuartmckenna/3104554689/ [14] http://www.flickr.com/photos/erikcharlton/421678891/
  83. 83. 83 Quellen Bilder (2/3) [15] http://www.flickr.com/photos/zkorb/1592677291/ [17] http://www.flickr.com/photos/mortimer/221051561/ [18] http://www.flickr.com/photos/flying_cloud/2666399483/ [19] http://www.flickr.com/photos/fattytuna/8586848/ [20] selbst fotografiert (Buch: Programming in Scala) [21] http://www.flickr.com/photos/travel_aficionado/2396824478/ [22] http://www.flickr.com/photos/webel/2406479887/ [23] http://www.flickr.com/photos/whisperwolf/3487084290/ [24] http://www.flickr.com/photos/adesigna/3237575990/ [25] http://www.flickr.com/photos/mugley/4207122005/ [26] http://www.flickr.com/photos/jof/263652571/ [27] http://www.flickr.com/photos/themonnie/2500388784/
  84. 84. 84 Quellen Bilder(3/3) [LOGOS] DB4O - http://www.db4o.com LIFT - http://www.liftweb.net WEBDSL - http://www.webdsl.org Squeryl - http://max-l.github.com/Squeryl ScalaTest - http://scalatest.org Grails - http://www.grails.org Scala - http://www.scala-lang.org Groovy - http://groovy.codehaus.org Ruby - http://ruby-lang.org Python – http://www.python.org
  85. 85. 85 License Präsentation http://creativecommons.org/licenses/by-nc-nd/3.0/de/ Quelltext http://www.apache.org/licenses/LICENSE-2.0.html

×