aestasit - internal dsls in scala

27
Internal DSLs in Scala Andrey Adamovich Aestas/IT

Upload: neueda

Post on 10-May-2015

1.362 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: AestasIT - Internal DSLs in Scala

Internal DSLs in ScalaAndrey AdamovichAestas/IT

Page 2: AestasIT - Internal DSLs in Scala

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

Page 3: AestasIT - Internal DSLs in Scala

WORLD OF DSLS

Page 4: AestasIT - Internal DSLs in Scala

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

Page 5: AestasIT - Internal DSLs in Scala

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.

Page 6: AestasIT - Internal DSLs in Scala

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

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

Fluent API examplesMockito

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

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

Page 11: AestasIT - Internal DSLs in Scala

SCALA

Page 12: AestasIT - Internal DSLs in Scala

Features of ScalaLightweight syntaxCombines functional and object-

oriented aproachesAdvanced type system:

everything has a typeStrong type inferencePerformance comparable to JavaFully interoperable with Java

Page 13: AestasIT - 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 namesImplicit conversionsAdvanced type systemBy-name parameters and

currying

Page 14: AestasIT - 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: AestasIT - 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: AestasIT - 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: AestasIT - 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 each with a single argument (partial application).

Page 18: AestasIT - 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: AestasIT - Internal DSLs in Scala

Advanced type system

Page 20: AestasIT - Internal DSLs in Scala

DSL EXAMPLES

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

Page 23: AestasIT - 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: AestasIT - Internal DSLs in Scala

READING MATERIAL

Page 25: AestasIT - Internal DSLs in Scala

Books

DSLs in ActionDebasish Ghosh

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

Venners

Page 27: AestasIT - Internal DSLs in Scala

QUESTIONS