The Artima Developer Community
Sponsored Link

Artima Developer Spotlight Forum
Designing an Internal DSL in Scala

7 replies on 1 page. Most recent reply: Jun 17, 2008 5:11 AM by David Newton

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 7 replies on 1 page
Frank Sommers

Posts: 2642
Nickname: fsommers
Registered: Jan, 2002

Designing an Internal DSL in Scala Posted: May 26, 2008 10:49 AM
Reply to this message Reply
Advertisement

Among the benefits of domain-specific languages is that, if designed well, less skilled programmers, and even business analysts and end-users, can use the DSL to interact with the system and construct programs from it.

One approach to defining a DSL is to invent a custom language with syntax that's custom-tailored to a business situation or requirement, and then write a parser that understands that language. Often, the parser will feed a syntax tree of a DSL program into a compiler that then translates the DSL into a general-purpose language, such as Java, or even Java bytecode.

By contrast, it is also possible to invent domain-specific syntax that can be used directly within a general-purpose language. Such syntax extensions differ from an API in that they provide a program model that especially suits a domain, such as Web applications or financial analysis. At the same time, users of that DSL can reach out to any facility provided by the general-purpose host language for tasks such as accessing other libraries or external resources and databases.

In a recent blog post, Designing Internal DSLs in Scala, Debasish Ghosh explains how to construct such an internal DSL with Scala as a host language. Because Scala interacts well with Java, this technique is especially well-suited to working with an existing enterprise Java application:

External DSLs involve parsing of syntax foreign to the native language - hence the ease of developing external DSLs depends a lot on parsing and parse tree manipulation capabilities available in existing libraries and frameworks. Internal DSLs are a completely different beast altogether, and singularly depends on the syntax and meta programming abilities that the language offers.

Ghosh defines a language for stock trading:

val orders = List[Order](

  // use premium pricing strategy for order
  new Order to buy(100 sharesOf "IBM")
            maxUnitPrice 300
            using premiumPricing,

  // use the default pricing strategy
  new Order to buy(200 sharesOf "GOOGLE")
            maxUnitPrice 300
            using defaultPricing,

  // use a custom pricing strategy
  new Order to sell(200 bondsOf "Sun")
            maxUnitPrice 300
            using {
              (qty, unit) => qty * unit - 500
            }
)

This DSL looks meaningful enough for the business analysts as well, since it uses the domain language and does not contain much of the accidental complexities that we get in languages like Java. The language provides easy options to plug in default strategies (e.g. for pricing orders, as shown above). Also it offers power users the ability to define custom pricing policies inline when instantiating the Order.

Ghosh lists several Scala features that make such a DSL easy to create, such as implicit and higher-order functions, currying, and methods that can act as operators.

What do you think of using Scala as a host language for internal DSLs?


Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: Designing an Internal DSL in Scala Posted: May 26, 2008 10:50 PM
Reply to this message Reply
> Among the benefits of domain-specific languages is that, if designed well, less skilled programmers, and even business analysts and end-users, can use the DSL to interact with the system and construct programs from it.

Lies, LIES! ALL OF IT, LIES!!

*ahem*

Excuse me.

cf. Genesis 11:1-9

Cheers,
Carson

Francois Bertrand

Posts: 2
Nickname: fbertra
Registered: May, 2008

Re: Designing an Internal DSL in Scala Posted: May 28, 2008 1:31 PM
Reply to this message Reply
Another example of DSL in Scala

http://activemq.apache.org/camel/scala-dsl.html

Compare with the Spring version: http://activemq.apache.org/camel/scala-dsl.html .

Outstanding.

Francois Bertrand

Posts: 2
Nickname: fbertra
Registered: May, 2008

Re: Designing an Internal DSL in Scala Posted: May 28, 2008 1:52 PM
Reply to this message Reply
Sorry, the Spring version is here: http://activemq.apache.org/camel/spring.html

Carson Gross

Posts: 153
Nickname: cgross
Registered: Oct, 2006

Re: Designing an Internal DSL in Scala Posted: May 29, 2008 10:38 AM
Reply to this message Reply
OK, let's test my assertion that the benefits of DSLs are not worth the costs. I'll try to rewrite some of the examples from the Camel page as best I can using an ideal statically typed language (I'll use GScript, our internal language)

From http://activemq.apache.org/camel/scala-dsl-getting-started.html

class MyRouteBuilder extends RouteBuilder {
"direct:a" --> "mock:a"
"direct:b" to "mock:b"
}


I might write a library that looked like this:

RouteBuilder.create( "MyRouteBuilder", {
Route.from("direct:a").to("mock:a"),
Route.from("direct:b").to("mock:b")
} )

Where we are passing an array of Routes to the RouteBuilder constructor. (The curlies inside the constructor indicate that an Array should be constructed.)

I'm assuming here that the creation of the class also registers the class in the underlying framework somehow.

A more complicated example is:

"direct:a" ==> {
to ("mock:polyglot")
choice {
when (_.in == "<hello/>") to ("mock:english")
when (_.in == "<hallo/>") {
to ("mock:dutch")
to ("mock:german")
}
otherwise to ("mock:french")
}
}


My naive first attempt at a library function similar to this in GScript is:

Route.from("direct:a")
.to("mock:polyglot")
.choice( \ obj, route ->
if( obj.in == "hello" ){
route.to( "mock:english" )
} else if( obj.in == "hallo" ) {
route.to( "mock:dutch" )
route.to( "mock:german" )
} else {
route.to( "mock:french" )
})

Yup, it's uglier, but the question is is it worth the costs of having a specialized language for routing, rather than just a library in a standard, existing language (with a good IDE supporting code-completion, one hopes.)

One thing I will say is that most general purpose imperative languages have a hard time expressing nested, hierarchically arranged objects nicely (Builder syntaxes start to fall down when things aren't linearized) but with a bit of work I think we could make them better at it.

Thoughts?

Cheers,
Carson

Victor Volle

Posts: 2
Nickname: vivo
Registered: Aug, 2006

Re: Designing an Internal DSL in Scala Posted: May 31, 2008 11:23 AM
Reply to this message Reply
If more than 25% (arbitrary but not to small number) of the code you have to write, are routing rules, it makes sense to create a DSL. More general: if the effort to create (and maintain and use!) a DSL is smaller than the effort to write the code in some normally used language X, it is worth the effort.

Wouldn't it be better to compare the DSL to a language that is "available" (instead of an internal language, where nearly no one can say, if your example is good w.r.t. the features of that language?).

Victor

Gregg Irwin

Posts: 16
Nickname: greggirwin
Registered: Jan, 2004

Re: Designing an Internal DSL in Scala Posted: Jun 16, 2008 2:13 PM
Reply to this message Reply
> OK, let's test my assertion that the benefits of DSLs are
> not worth the costs.

Doesn't that question apply to everything? You have to weigh the cost and benefit on a case by case basis. How much effort does it take to create and maintain the language compared to the things written *in* the language?

For example, given the mock translations below for my language of choice, how much code and time would you approve of to implement such a dialect/DSL if the number of routes you expect to write is:

1) less than 10
2) from 10 to 100
3) from 100 to 500
4) more than 500

(anyone case respond, the more the merrier)


RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("seda:a").to("seda:b");
}
};

rte: route [seda:a to seda:b]


class MyRouteBuilder extends RouteBuilder {
"direct:a" --> "mock:a"
"direct:b" to "mock:b"
}

rte: route [
direct:a to mock:a
direct:b to mock:b
]


RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("seda:a").choice().when(header("foo").isEqualTo("bar")).to("seda:b")
.when(header("foo").isEqualTo("cheese")).to("seda:c").otherwise().to("seda:d");
}
};

rte: route [
seda:a to [
seda:b when header "foo" is "bar"
seda:c when header "foo" is "cheese"
seda:d otherwise
]
]


I'm not sure I would use a DSL in this case myself. It would depend on the desired functionality.

David Newton

Posts: 2
Nickname: davenewton
Registered: Dec, 2007

Re: Designing an Internal DSL in Scala Posted: Jun 17, 2008 5:11 AM
Reply to this message Reply
@Carson: What's the difference between an "internal DSL" and a library? AFAICT almost nothing except they read marginally better, and that depends entirely on the implementation language.

If you had attempted your argument against *external* DSLs you'd have a stronger point.

Flat View: This topic has 7 replies on 1 page
Topic: Designing an Internal DSL in Scala Previous Topic   Next Topic Topic: 5 Things Grady Booch Has Learned About Complex Software

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use