Internal DSLs in Scala

27
Internal DSLs in Scala Andrey Adamovich Aestas/IT

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 of Internal DSLs in Scala

Page 1: Internal DSLs in Scala

Internal DSLs in Scala

Andrey Adamovich

Aestas/IT

Page 2: Internal DSLs in Scala

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

Page 3: Internal DSLs in Scala

WORLD OF DSLSWORLD OF DSLSWORLD OF DSLSWORLD OF DSLS

Page 4: Internal DSLs in Scala

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).

Page 5: Internal DSLs in Scala

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.

Page 6: Internal DSLs in Scala

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

Page 7: Internal DSLs in Scala

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

Page 8: Internal DSLs in Scala

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

Page 9: Internal DSLs in Scala

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).

Page 10: Internal DSLs in Scala

Fluent API examples

Mockito

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

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

Page 11: Internal DSLs in Scala

SCALASCALASCALASCALA

Page 12: Internal DSLs in Scala

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

Page 13: Internal DSLs in Scala

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

Page 14: Internal DSLs in Scala

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

Page 15: Internal DSLs in Scala

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))

}

Page 16: Internal DSLs in Scala

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()

}

Page 17: Internal DSLs in Scala

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).

Page 18: Internal DSLs in Scala

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()

}

}

Page 19: Internal DSLs in Scala

Advanced type system

Page 20: Internal DSLs in Scala

DSL DSL DSL DSL EXAMPLESEXAMPLESEXAMPLESEXAMPLES

Page 21: Internal DSLs in Scala

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:

Page 22: Internal DSLs in 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

Page 23: Internal DSLs in Scala

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")

Page 24: Internal DSLs in Scala

READING MATERIALREADING MATERIALREADING MATERIALREADING MATERIAL

Page 25: Internal DSLs in Scala

Books

DSLs in Action

Debasish Ghosh

Programming in Scala, Second Edition

Martin Odersky, Lex Spoon, and Bill Venners

Page 26: Internal DSLs in Scala

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/

Page 27: Internal DSLs in Scala

QUESTIONSQUESTIONSQUESTIONSQUESTIONS