AestasIT - Internal DSLs in Scala

Post on 10-May-2015

1.356 views 3 download

Tags:

Transcript of AestasIT - Internal DSLs in Scala

Internal DSLs in ScalaAndrey AdamovichAestas/IT

What’s in this presentation?Definition and usage of DSLsOverview of Scala features that

can be used to create internal DSL

Examples of Scala-based DSLsSome links and reading materialQuestions

WORLD OF DSLS

What is DSL?

Domain-Specific LanguageA 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: HTML, Logo for children, Verilog and VHDL hardware description

languages, Mata for matrix programming, Mathematica and Maxima for symbolic

mathematics, spreadsheet formulas and macros, SQL for relational database queries, YACC grammars for creating parsers, regular expressions for specifying lexers, the Generic Eclipse Modeling System for

creating diagramming languages, Csound for sound and music synthesis, and the input languages of GraphViz and GrGen,

software packages used for graph layout and graph rewriting.

Goals of DSL Use a more expressive language than a

general-purpose one Share a common metaphor of

understanding between developers and subject matter experts

Have domain experts help with the design of the business logic of an application

Avoid cluttering business code with too much boilerplate technical code thanks to a clean separation

Let business rules have their own 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 examplesMockito

Guava http://code.google.com/p/guava-libraries/

http://code.google.com/p/mockito/

SCALA

Features of ScalaLightweight syntaxCombines functional and object-

oriented aproachesAdvanced type system:

everything has a typeStrong type inferencePerformance comparable to JavaFully 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 namesImplicit conversionsAdvanced type systemBy-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 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 EXAMPLES

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 DSLimport 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 MATERIAL

Books

DSLs in ActionDebasish Ghosh

Programming in Scala, Second EditionMartin Odersky, Lex Spoon, and Bill

Venners

QUESTIONS