Scala: the language of languages - Mario Fusco (Red Hat)


Published on

Scala meetup - Milan, 25 May 2013

Molte caratteristiche di Scala sono state appositamente pensate (o almeno lo sembrano) per favorire la sviluppo di Domain Specific Languages. Ad esempio le conversioni implicite e le funzioni con più set di parametri è possibile progettare DSL interni molto leggibili, mentre i parser combinator consentono di sviluppare DSL esterni con un minimo sforzo. Lo scopo del talk è quello di mostrare il funzionamento di queste tecniche e strumenti con esempi pratici.

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Scala: the language of languages - Mario Fusco (Red Hat)

  1. 1. by Mario FuscoRed Hat – Senior Software Engineermario.fusco@gmail.comtwitter: @mariofuscoScalathe languageof languages
  2. 2. What is aDomain Specific Language?Acomputer programming languageoflimited expressivenessfocused on aparticular domaincomputer programming languagelimited expressivenessparticular domain
  3. 3. 2 principles driving towardDSL developmentWhy use aDomain Specific Language?
  4. 4. The only purpose oflanguages,even programming onesIS COMMUNICATIONCommunication is king
  5. 5. Written once, read many timesAlways code asif the personwho willmaintain yourcode is a maniacserial killer thatknows whereyou live
  6. 6. "Any fool can write codethat a computer canunderstand.Good programmerswrite code that humanscan understand“Martin Fowler
  7. 7. Pros & Cons of DSLs+ Expressivity  Communicativity+ Conciseness+ Readability  Maintainability  Modificability+ Higher level of abstraction+ Higher productivity in the specific problem domain̶ Language design is hard̶ Upfront cost̶ Additional indirection layer  Performance concerns̶ Lack of adeguate tool support̶ Yet-another-language-to-learn syndrome
  8. 8. DSL taxonomy External DSL  a language having customsyntactical rules separate from the main language ofthe application it works with Internal DSL  a particular way of employing ageneral-purpose language, using only a small subsetof the languages features Language workbench  a specialized IDE fordefining and building DSL, usually in a visualway, used both to determine the structure of theDSL and to provide an editing environment forpeople using it
  9. 9. Internal DSLExternal DSLDSL Types Comparison+ learning curve+ cost of building+ programmers familiarity+ IDE support (autocompletion …)+ composability+ flexibility+ readability+ clear separation betweenbusiness (DSL) and host language+ helpful when business code iswritten by a separate team(domain experts)̶ syntactic noise̶ needs to be recompiled(if host language is static)̶ need to learn of grammarsand language parsing̶ boundary between DSLand host language̶ easier to grow out ofcontrol
  10. 10. Internal DSLin Scala
  11. 11. Scala features for internal DSLImplicit conversionimplicit def intToRational(x: Int) = new Rational(x)val c = 2 + a // = 8/3Higher-Order Functionsdef twice(f: => Unit): Unit = { f; f; }twice {println("Hello World")}
  12. 12. A more complete exampleHammurabiA Scala rule engine
  13. 13. The golfers problem• A foursome of golfers is standing at a tee, in a line from left toright. Each golfer wears different colored pants; one iswearing red pants.• The golfer to Fred’s immediate right is wearing blue pants.• Joe is second in line.• Bob is wearing plaid pants.• Tom isn’t in position one or four, and he isn’t wearing thehideous orange pants.• In what order will the four golfers tee off, and what color areeach golfer’s pants?”
  14. 14. The Hammurabi Solution (1)var allPos = (1 to 4).toSetvar allColors =Set("blue", "plaid", "red", "orange")val assign = new {def position(p: Int) = new {def to(person: Person) = {person.pos = pallPos = availablePos - p}}def color(c: String) = new {def to(person: Person) = {person.color = callColors = availableColors - c}}}class Person(n: String) {val name = nvar pos: Int = _var color: String = _}
  15. 15. The Hammurabi Solution (2)import hammurabi.Rule._val ruleSet = Set(rule ("Unique positions") let {val p = any(kindOf[Person])when {(availablePos.size equals 1) and (p.pos equals 0)} then {assign position availablePos.head to p}},[……]rule ("Person to Fred’s immediate right is wearing blue pants") let {val p1 = any(kindOf[Person])val p2 = any(kindOf[Person])when {( equals "Fred") and (p2.pos equals p1.pos + 1)} then {assign color "blue" to p2}})
  16. 16. How Hammurabi DSL works (1)case class Rule(description: String,bind: () => RuleDefinition[_], salience: Int = 0)case class RuleDefinition[A](condition: () => Boolean,execution: () => A)def rule(description: String) = new {def let(letClause: => RuleDefinition[_]): Rule =Rule(description, letClause _)def withSalience(salience: Int) = new {def let(letClause: => RuleDefinition[_]): Rule =Rule(description, letClause _, salience)}}rule ("An extremly useful rule") withSalience 5 let {...}
  17. 17. How Hammurabi DSL works (2)def when(condition: => Boolean) = new {def then[A](execution: => A): RuleDefinition =RuleDefinition(condition _, execution _)}rule("Joe is in position 2") let {val p = any(kindOf[Person])when { equals "Joe"} then {assign position 2 to p}}def ruleExecution() = {val ruleDef = rule.bind()if (ruleDef.condition()) ruleDef.execution()}
  18. 18. External DSLin Scala
  19. 19. A Scala Parserabstract class Parser[+T] extends (Input => ParserResult[T])trait Parsers {sealed abstract class ParseResult[+T] { val next: Input }case class Success[+T](result: T, override val next: Input)extends ParseResult[T] { ... }sealed abstract class NoSuccess(val msg: String,override val next: Input)extends ParseResult[Nothing] { ... }case class Failure(override val msg: String,override val next: Input)extends NoSuccess(msg, next) { ... }case class Error(override val msg: String,override val next: Input)extends NoSuccess(msg, next) { ... }}
  20. 20. Parser CombinatorsCombinator Symbol DescriptionSequence ~ If two parsers P and Q are combined using the sequentialcombinator, the parsing succeeds if:■ P successfully consumes a part of the input stream■ Q following P consumes the input that P did not consumeAlternation | A parser combinator for composing alternatives.Selectivesequence~><~Selectively keep only either the right or the left result of asequence combinatorRepetition rep… A combinator that works on a parser P and returns anotherparser that parses one or more repetitions of what P parsesFunctionapplication^^^^^A combinator that allows a function to be applied on aparser, resulting in a new parser.Variation Explanation(rep(p), p*) Repeat p 0+ times(rep1(p), p+) Repeat p 1+ times(repN(n, p)) Repeat p exactly n times