Writing an internal DSL in scala
Jiří Kremser
2014-02-07
Outline
- Scala basics
- External/Internal DSL
- Scala DSL-friendly features
- Coding
- ..more coding
- ..even more coding
Motivation
import collection.mutable.Stack import org.scalatest._ class ExampleSpec extends FlatSpec with Matchers { "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 be (2) stack.pop() should be (1) } it should "throw NoSuchElementException if an empty stack is popped" in { val emptyStack = new Stack[Int] a [NoSuchElementException] should be thrownBy { emptyStack.pop() } } }
Scala basics
- JVM based
- Compiled to bytecode
- OOP
- Functional paradigm
- Type safety
- "SCAlable LAnguage"
Scala vs Java
Scala Java
variables
|
|
methods
|
|
Scala vs Java
Scala Java
classes
+ equals() & hashcode() + toString() + pattern matching |
|
Higher order functions
val evenNums = (1 to 1000).filter(x => x % 2 == 0)
val evenNums = (1 to 1000).filter(_ % 2 == 0)
def isEven = _ % 2 == 0
val evenNums = (1 to 1000) filter isEven
val evenNums = for (i <- 1 to 1000; if i % 2 == 0) yield i)
val evenNums = for (i <- 1 to 500) yield 2 * i)
val evenNums = 2 to 1000 by 2
def foo(f1: (String => Int), f2: (Int => String)) = f1 andThen f2
val obfuscate = foo(_.length, "*" * _)
Domain specific language
- serves one purpose (is not Turing-complete)
- language implies communication
- useful for higher lvl abstraction
- well designed DSL has great marketing value
- External vs Internal DSLs
- from fluent API to natural language
bind(String.class)
.annotatedWith(Names.named("JDBC URL"))
.toInstance("jdbc:mysql://localhost/pizza");
External dsl
-
CSS,
SQL, SPARQL, "*QL", etc.
- compiled / interpreted
- requires some toolkit to design the lang.
- ANTLR, IntelliJ MPS, Eclipse Xtext
- programs represented as strings / XMLs / JSONs
- mostly, no compile time validation
Internal DSL
- language constructs = host language
- host lang. is type safe → DSL may be type safe
- fluent APIs (builder pattern)
- suitable languages: Scala, Ruby, Clojure (Lisp), Groovy
- good practice: no side effects, just build an object
- ..then pass the object to a method (M. Fowler)
Scala and DSL
- Implicit conversions
class IntWrapper(val value: Int) {
def C = s"$value degrees" // same as value + "degrees"
}
implicit def Int2IntWrapper(value: Int) = new IntWrapper(value)
- Anonymous classes
(new {
def foo() = "bar"
}).foo()
Scala and DSL
- Method calling
one argument
|
|
no argument
|
|
Scala and DSL
- Method calling again
precedence rules
|
|
Scala and DSL
- built in support for external DSLs
- combinators: ~, |, ~>, <~, ^^
- example: http://git.io/XeJh-g
Talk is cheap, let's code
Scala Installation
Scala Hello Wold App
println("Hello World!")
...
Thats all folks
Feedback
This presentation
Writing an internal DSL
By jkremser
Writing an internal DSL
- 808