Septeni Technology
09/2017
Programming & Photography
Hello!
I Am ThuNX
@hitamu
in Scala
Domain Specific Language
Agenda
DSL in Scala
What is Domain Specific Language (DSL)
Why using DSL
Conclusion
Domain Specific Language
What is DSL ?
Problem Domain
Mapping
Solution Domain
What is Domain
Domain Specific Language
“ A domain-specific language (DSL) is a computer
language specialized to a particular application
domain. ”
● Parsed independently of the host general
purpose language (Regular Expression)
● Can be much richer in syntax
External DSL
● Written inside an existing host language.
(Scalikejdbc, Scalatest...)
● More readable & can be closed to natural
language
Internal DSL
Type of DSL
But why ?
Take out the apple core
Simple task, don’t need to worry
Common tools
Problem comes up
!!!
Right tool for right job
DSL in Scala
● Type-safe
● Implicits
● Higher order functions
● Optional dots, semi-colons and parentheses
● Currying
Example
42 ($) + 35 (€) = ? (£)
Money DSL (1)
object Currency {
object USD extends Currency {
val getCode: String = "USD"
}
object EUR extends Currency {
val getCode: String = "EUR"
}
object GBP extends Currency {
val getCode: String = "GBP"
}
def apply(s: String): Currency = s.toUpperCase match {
case "USD" => USD
case "EUR" => EUR
case "GBP" => GBP
}
}
type Conversion = Map[(Currency, Currency), BigDecimal]
val conversion: Conversion = Map(
(GBP, EUR) -> 1.39,
(EUR, USD) -> 1.08,
(GBP, USD) -> 1.5
)
case class Converter(conversion: Conversion) extends {
def convert(from: Currency, to: Currency): BigDecimal = {
if (from == to) 1
else conversion.getOrElse((from, to), 1 /
conversion((to, from)))
}
}
Money DSL (2)
case class Money(amount: BigDecimal, currency: Currency,
converter: Converter)
def +(thatMoney: Money): Money =
performOperation(thatMoney, _ + _)
def performOperation(thatMoney: Money, operation:
(BigDecimal, BigDecimal) => BigDecimal): Money = {
thatMoney match {
case Money(v, c) if c == currency =>
Money(operation(amount, v), currency)
case Money(v, c) =>
performOperation(thatMoney.to(currency), operation)
}
}
def to(thatCurrency: Currency): Money = {
val rate = converter.convert(currency, thatCurrency)
Money(amount * rate, thatCurrency)
// Main class
val conversion: Conversion = Map(
(GBP, EUR) -> 1.39,
(EUR, USD) -> 1.08,
(GBP, USD) -> 1.50
)
val converter = Converter(conversion)
// Sum up then exchange
val result = Money(42, USD, converter) + Money(35, EUR,
converter)
result.to(GBP)
Money DSL (3)
case class Money(amount: BigDecimal, currency:
Currency)(implicit converter: Converter)
implicit class BigDecimalOps(value: BigDecimal) {
def apply(currency: Currency)(implicit converter:
Converter): Money = Money(value, currency)
}
implicit class IntOps(value: Int) {
def apply(currency: Currency)(implicit converter:
Converter): Money = (value: BigDecimal).apply(currency)
}
implicit class DoubleOps(value: Double) {
def apply(currency: Currency)(implicit converter:
Converter): Money = (value: BigDecimal).apply(currency)
}
// Better with implicit
val dollars = 100(USD)
val euros = 42.24(EUR)
// Main class
val conversion: Conversion = Map(
(GBP, EUR) -> 1.39,
(EUR, USD) -> 1.08,
(GBP, USD) -> 1.50
)
implicit val converter = Converter(conversion)
// More readable
val result = 42(USD) + 35(EUR) to GBP
Money DSL (4)
// Sum up then exchange
val result =
Money(42, USD, converter) +
Money(35, EUR, converter)
val resultToPound = result.to(GBP)
// Sum up then exchange
val result = 42(USD) + 35(EUR) to GBP
Boring Style Brilliant DSL
● Design is hard
● Upfront cost
● Can be lead to performance concern
Cons
● More expressive than general language
● Concise
● High level abstraction
Pros
Conclusion
References
● https://github.com/siddhuwarrier/scala-dsl-tutorial
● http://www.devx.com/enterprise/introduction-to-internal-dsls-i
n-scala.html
● https://www.slideshare.net/krikava/domain-specific-languages-a
nd-scala
● Book: Domain Specific Language in Action
Thanks!
Any questions?

DSL in scala

  • 1.
  • 2.
  • 3.
  • 4.
    Agenda DSL in Scala Whatis Domain Specific Language (DSL) Why using DSL Conclusion
  • 5.
  • 6.
  • 7.
    Domain Specific Language “A domain-specific language (DSL) is a computer language specialized to a particular application domain. ”
  • 8.
    ● Parsed independentlyof the host general purpose language (Regular Expression) ● Can be much richer in syntax External DSL ● Written inside an existing host language. (Scalikejdbc, Scalatest...) ● More readable & can be closed to natural language Internal DSL Type of DSL
  • 9.
  • 10.
    Take out theapple core Simple task, don’t need to worry
  • 11.
  • 12.
  • 13.
    Right tool forright job
  • 14.
    DSL in Scala ●Type-safe ● Implicits ● Higher order functions ● Optional dots, semi-colons and parentheses ● Currying
  • 15.
    Example 42 ($) +35 (€) = ? (£)
  • 16.
    Money DSL (1) objectCurrency { object USD extends Currency { val getCode: String = "USD" } object EUR extends Currency { val getCode: String = "EUR" } object GBP extends Currency { val getCode: String = "GBP" } def apply(s: String): Currency = s.toUpperCase match { case "USD" => USD case "EUR" => EUR case "GBP" => GBP } } type Conversion = Map[(Currency, Currency), BigDecimal] val conversion: Conversion = Map( (GBP, EUR) -> 1.39, (EUR, USD) -> 1.08, (GBP, USD) -> 1.5 ) case class Converter(conversion: Conversion) extends { def convert(from: Currency, to: Currency): BigDecimal = { if (from == to) 1 else conversion.getOrElse((from, to), 1 / conversion((to, from))) } }
  • 17.
    Money DSL (2) caseclass Money(amount: BigDecimal, currency: Currency, converter: Converter) def +(thatMoney: Money): Money = performOperation(thatMoney, _ + _) def performOperation(thatMoney: Money, operation: (BigDecimal, BigDecimal) => BigDecimal): Money = { thatMoney match { case Money(v, c) if c == currency => Money(operation(amount, v), currency) case Money(v, c) => performOperation(thatMoney.to(currency), operation) } } def to(thatCurrency: Currency): Money = { val rate = converter.convert(currency, thatCurrency) Money(amount * rate, thatCurrency) // Main class val conversion: Conversion = Map( (GBP, EUR) -> 1.39, (EUR, USD) -> 1.08, (GBP, USD) -> 1.50 ) val converter = Converter(conversion) // Sum up then exchange val result = Money(42, USD, converter) + Money(35, EUR, converter) result.to(GBP)
  • 18.
    Money DSL (3) caseclass Money(amount: BigDecimal, currency: Currency)(implicit converter: Converter) implicit class BigDecimalOps(value: BigDecimal) { def apply(currency: Currency)(implicit converter: Converter): Money = Money(value, currency) } implicit class IntOps(value: Int) { def apply(currency: Currency)(implicit converter: Converter): Money = (value: BigDecimal).apply(currency) } implicit class DoubleOps(value: Double) { def apply(currency: Currency)(implicit converter: Converter): Money = (value: BigDecimal).apply(currency) } // Better with implicit val dollars = 100(USD) val euros = 42.24(EUR) // Main class val conversion: Conversion = Map( (GBP, EUR) -> 1.39, (EUR, USD) -> 1.08, (GBP, USD) -> 1.50 ) implicit val converter = Converter(conversion) // More readable val result = 42(USD) + 35(EUR) to GBP
  • 19.
    Money DSL (4) //Sum up then exchange val result = Money(42, USD, converter) + Money(35, EUR, converter) val resultToPound = result.to(GBP) // Sum up then exchange val result = 42(USD) + 35(EUR) to GBP Boring Style Brilliant DSL
  • 20.
    ● Design ishard ● Upfront cost ● Can be lead to performance concern Cons ● More expressive than general language ● Concise ● High level abstraction Pros Conclusion
  • 21.
    References ● https://github.com/siddhuwarrier/scala-dsl-tutorial ● http://www.devx.com/enterprise/introduction-to-internal-dsls-i n-scala.html ●https://www.slideshare.net/krikava/domain-specific-languages-a nd-scala ● Book: Domain Specific Language in Action
  • 22.