Internal DSLs in Scala
-
Upload
aestas-it -
Category
Technology
-
view
1.900 -
download
4
description
Transcript of Internal DSLs in Scala
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