Domain Specific Languages #DUSE-3
Peter Maas  ~ Developer at Ebay Classifieds, working at the Marktplaats.nl migration. Likes programming languages. whoami
Agenda What is a DSL?
What makes Scala a good language for DSLs
Internal DSL
External DSL ACTUAL CODE!
Questions? Feel free to interrupt!
So, what is a DSL a  D omain- S pecific  L anguage (DSL) is a programming language or specification language dedicated to a particular problem domain, a particular problem representation technique, and/or a particular solution technique.
A language which feels natural to a specialist in the targeted domain
Internal / External Internal DSLs are built using the language itself. Buildr
Gradle
Routing configuration in Apache Camel External DSLs are 'mini' programming languages with their own compiler/interpreter SQL
Velocity
Why is Scala good at that Concise and tolerant syntax
Function objects (closures, currying etc)
Default arguments
Operator overloading
Implicit conversions

Domain Specific Languages In Scala Duse3

  • 1.
  • 2.
    Peter Maas ~ Developer at Ebay Classifieds, working at the Marktplaats.nl migration. Likes programming languages. whoami
  • 3.
  • 4.
    What makes Scalaa good language for DSLs
  • 5.
  • 6.
  • 7.
    Questions? Feel freeto interrupt!
  • 8.
    So, what isa DSL a D omain- S pecific L anguage (DSL) is a programming language or specification language dedicated to a particular problem domain, a particular problem representation technique, and/or a particular solution technique.
  • 9.
    A language whichfeels natural to a specialist in the targeted domain
  • 10.
    Internal / ExternalInternal DSLs are built using the language itself. Buildr
  • 11.
  • 12.
    Routing configuration inApache Camel External DSLs are 'mini' programming languages with their own compiler/interpreter SQL
  • 13.
  • 14.
    Why is Scalagood at that Concise and tolerant syntax
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
    Built-in support forbuilding parsers
  • 20.
    Due to it'sfunctional nature it is good at handling syntax trees.
  • 21.
    Concise? val toGreet = " Marktplaats developers"  "Hello" . + ( toGreet )   "Hello" + toGreet   "Hello" . concat ( toGreet ) "Hello" concat toGreet   // methods are objects...   val greetMethod = "hello %s".format(_:String) greetMethod(toGreet)
  • 22.
    Implicit conversions class StringReducer(s:String) { def acronym = s.filter(_.isUpper) } implicit def string2StringReducer(s:String) = new StringReducer(s) "Sun Certified Java Programmer".acronym == "SCJP"
  • 23.
    Or... case class Route(source:String, target:String) class RouteBuilder(s:String) { def --> (target:String) = Route(s, target) } implicit def string2Route(s:String) = new RouteBuilder(s) "a" --> "b" == Route( "a" , "b" )
  • 24.
    Let's build aDSL we all know SQL http://github.com/p3t0r/scala-sql-dsl
  • 25.
    Pure Scala //Simple query with sorting SQL select "*" from ("user") order Asc("name") // More complex query with and/or including precedence SQL select "*" from ("user") where (("name","peter") and (("active", true) or ("role", "admin"))) Overriding the '=' operator was a no-go ;-)
  • 26.
  • 27.
    case class Where( val clauses: Clause*) trait Clause { def and (otherField: Clause): Clause = And(this, otherField) def or (otherField: Clause): Clause = Or(this, otherField) } case class StringEquals(val f: String, val value: String) extends Clause case class NumberEquals(val f: String, val value: Number) extends Clause case class BooleanEquals(val f: String, val value: Boolean) extends Clause case class In(val field: String, val values: String*) extends Clause case class And(val lClause:Clause, val rClause:Clause) extends Clause case class Or(val lClause:Clause, val rClause:Clause) extends Clause AST for the Where clause
  • 28.
    Some Implicits &Helpers object QueryBuilder { implicit def tuple2field(t: (String, String)): StringEquals = StringEquals(t._1, t._2) implicit def tuple2field(t: (String, Int)): NumberEquals = NumberEquals(t._1, t._2) implicit def tuple2field(t: (String, Boolean)): BooleanEquals = BooleanEquals(t._1, t._2) implicit def from2query(f: From): Query = Query(f.operation.get, f, Option(Where())) /** entrypoint for starting a select query */ def select(fields:String*) = Select(fields:_*) def select(symbol: Symbol): Select = symbol match { case 'all => select("*") case _ => throw new RuntimeException("Only 'all allowed as symbol") } def in(field: String, values: String*) = In(field, values: _*) }
  • 29.
    That looks likea lot of code :( The entire builder is only 54 lines, including whitespace and comments! >> CONTINUE IN IDEA <<
  • 30.
    And external? class SQLParser extends JavaTokenParsers { def query:Parser[Query] = operation ~ from ~ opt(where) ~ opt(order) ^^ { case operation ~ from ~ where ~ order => Query(operation, from, where, order) } def operation:Parser[Operation] = { (&quot;select&quot; | &quot;update&quot; | &quot;delete&quot;) ~ repsep(ident, &quot;,&quot;) ^^ { case &quot;select&quot; ~ f => Select(f:_*) case _ => throw new IllegalArgumentException(&quot;Operation not implemented&quot;) } } def from:Parser[From] = &quot;from&quot; ~> ident ^^ (From(_)) def where:Parser[Where] = &quot;where&quot; ~> rep(clause) ^^ (Where(_:_*)) /* more in idea */ }