internal dsls in scala
DESCRIPTION
This presentation was given at JUG.lv meeting on 3rd of May in 2012. It tries to give audience a distinction between internal DSL and fluent interface, gives overview of Scala features that make internal DSLs possible in Scala and gives some examples of those DSLs.TRANSCRIPT
Internal DSLs in Scala
Andrey Adamovich
Aestas/IT
What’s in this presentation?
� Definition and usage of DSLs
� Overview of Scala features that can
be used to create internal DSL
� Examples of Scala-based DSLs
� Some links and reading material
� Questions
WORLD OF DSLSWORLD OF DSLSWORLD OF DSLSWORLD OF DSLS
What is DSL?
DDDDomain-SSSSpecific LLLLanguage
A Domain-Specific Language is a programming language or
executable specification language that offers, through
appropriate notations and abstractions, expressive power
focused on, and usually restricted to, a particular problem
domain.
”
The opposite is:
• a general-purpose programming language, such as C,
Java or Python,
• or a general-purpose modeling language such as the
Unified Modeling Language (UML).
”
Examples of DSL
� Examples of domain-specific languages include:
� HTMLHTMLHTMLHTML,
� LogoLogoLogoLogo for children,
� VerilogVerilogVerilogVerilog and VHDLVHDLVHDLVHDL hardware description languages,
� MataMataMataMata for matrix programming,
� MathematicaMathematicaMathematicaMathematica and MaximaMaximaMaximaMaxima for symbolic mathematics,
� spreadsheet formulas and macros,
� SQLSQLSQLSQL for relational database queries,
� YACCYACCYACCYACC grammars for creating parsers,
� regularregularregularregular expressionsexpressionsexpressionsexpressions for specifying lexers,
� the GenericGenericGenericGeneric EclipseEclipseEclipseEclipse ModelingModelingModelingModeling SystemSystemSystemSystem for creating
diagramming languages,
� CsoundCsoundCsoundCsound for sound and music synthesis,
� and the input languages of GraphVizGraphVizGraphVizGraphViz and GrGenGrGenGrGenGrGen,
software packages used for graph layout and graph
rewriting.
”
Goals of DSL
� Use a more expressive more expressive more expressive more expressive language than a general-
purpose one
� Share a common metaphor of common metaphor of common metaphor of common metaphor of understanding understanding understanding understanding
between developers and subject matter experts
� Have domain experts help domain experts help domain experts help domain experts help with the design of the
business logic of an application
� Avoid cluttering business code with too much too much too much too much
boilerplate technical boilerplate technical boilerplate technical boilerplate technical code code code code thanks to a clean
separation
� Let business rules have their own lifecycleown lifecycleown lifecycleown lifecycle
Guillaume LaforgeGroovy Project Manager
”
What is internal DSL?
Internal DSLs are particular ways
of using a host language to give
the host language the feel of a
particular language
”
Martin Fowler
Library vs. DSL
� Is there any difference between a
well-structured library or API and an
internal DSL?
� Not much, except for the following:
• Internal DSL does not look like code in
host language
• It’s more readable in general and is
much closer to natural language
Fluent API
In software engineering, a fluent interface
(as first coined by Eric Evans and Martin
Fowler) is an implementation of an object
oriented API that aims to provide for more
readable code.
”
A fluent interface is normally
implemented by using method chaining
to relay the instruction context of a
subsequent call (but a fluent interface
entails more than just method chaining).
”
Fluent API examples
Mockito
Guava http://code.google.com/p/guava-libraries/
http://code.google.com/p/mockito/
SCALASCALASCALASCALA
Features of Scala
� Lightweight syntax
� Combines functional and object-
oriented aproaches
� Advanced type system: everything
has a type
� Strong type inference
� Performance comparable to Java
� Fully interoperable with Java
What makes internal DSL possible
in Scala?
� ”Dot-free”, infix and postfix operator
notation
� ”Bracket-free” function calls
� (Almost) any character can be used
in method names
� Implicit conversions
� Advanced type system
� By-name parameters and currying
Lightweight syntax
val numbers = List(1, 2, 3)
numbers map { x => x + 1 }
numbers sortWith { (x, y) => x > y }
numbers map { _ + 1 } sortWith { _ > _ }
numbers size
Implicit conversions
Map( "first" -> "Test", "second" -> "Code" )
/* Defines a new method 'sort' for array objects */
object implicits extends Application {
implicit def arrayWrapper[A : ClassManifest](x: Array[A]) =
new {
def sort(p: (A, A) => Boolean) = {
util.Sorting.stableSort(x, p); x
}
}
val x = Array(2, 3, 1, 4)
println("x = "+ x.sort((x: Int, y: Int) => x < y))
}
By-name parameters
debug("This" + " is" + " very" + " costly!")
def debug(msg: => String): Unit =
if (isDebugEnabled()) println(msg)
spawn(println("I run in different thread!"))
def spawn(p: => Unit) = {
val t = new Thread() { override def run() = p }
t.start()
}
Curryng I
In mathematics and computer science,
currying is the technique of
transforming a function that takes
multiple arguments (or an n-tuple of
arguments) in such a way that it can be
called as a chain of functions chain of functions chain of functions chain of functions each with
a single argument (partial application).
”
Curryng II
using(new BufferedReader(new FileReader("file"))) { r =>
var count = 0
while (r.readLine != null) count += 1
println(count)
}
def using[T <: { def close() }]
(resource: T)
(block: T => Unit)
{
try {
block(resource)
} finally {
if (resource != null) resource.close()
}
}
Advanced type system
DSL DSL DSL DSL EXAMPLESEXAMPLESEXAMPLESEXAMPLES
Baysick
object ScalaBasicRunner extends Baysick with Application {
10 PRINT "Scala"
20 LET ('number := 1)
30 IF 'number > 0 THEN 50
40 PRINT "Java"
50 PRINT "rulez!"
60 END
RUN
}
ScalaBasicRunner.scala:
Time DSL
import org.scala_tools.time.Imports._
DateTime.now
DateTime.now.hour(2).minute(45).second(10)
DateTime.now + 2.months
DateTime.nextMonth < DateTime.now + 2.months
DateTime.now to DateTime.tomorrow
(DateTime.now to DateTime.nextSecond).millis
2.hours + 45.minutes + 10.seconds
(2.hours + 45.minutes + 10.seconds).millis
2.months + 3.days
Spring Integration DSL
val messageFlow =
filter using
{ payload: String => payload == "World" } -->
transform using
{ payload: String => "Hello " + payload } -->
handle using
{ payload: String => println(payload) }
messageFlow.send("World")
READING MATERIALREADING MATERIALREADING MATERIALREADING MATERIAL
Books
DSLs in Action
Debasish Ghosh
Programming in Scala, Second Edition
Martin Odersky, Lex Spoon, and Bill Venners
Links
� http://www.scala-lang.org/
� https://github.com/jorgeortiz85/scala-time
� http://blog.springsource.org/2012/03/05/introducing-spring-integration-scala-dsl/
� http://blog.fogus.me/2009/03/26/baysick-a-scala-dsl-implementing-basic/
� http://habrahabr.ru/post/98288/
QUESTIONSQUESTIONSQUESTIONSQUESTIONS