• Home
  • Events
  • About
  • The Art of Groovy Command Expressions in DSLs

    Domain Specific Languages (DSLs) are often littered with the accidental complexity of the host language. Have you ever seen a supposedly “friendly” language expression like “ride(minutes(10)).on(bus).towards(Basel)”. The newest version of Groovy contains a language feature that aims to eliminate the noise of all those extra periods and parenthesis, so that your DSL looks more like “ride 10.minutes on bus towards Basel”. This article shows you step-by-step how to use Groovy Command Expressions and plain old metaprogramming to write just this DSL, and also offers advice on when, and when not, to use this new language feature.

    The State of the Art with DSLs

    Domain Specific Languages (DSLs) have been in vogue for a long time, and the topic has featured regularly at No Fluff shows for years now. The value proposition of a DSL rests in the idea that programmers and users benefit from expressing their desires in a language closer to English than to Java, using words suited to the problem domain rather than the programming language. The goal is not to create an entire new language, but to create a small language just big enough for users to capture their commands and intents in a more natural way than is typically possible in code.

    Different languages support DSLs in various ways. Some languages make it easy to write nice, readable natural language-ish code and others do not. Over the next few pages we’ll explore the state of the art with Groovy DSLs, starting with looking at some unimaginative Groovy code, seeing how to convert into a better fluent interface, transforming it further using metaprogramming, and finally showing the full power of Groovy Command Expressions. As a sample problem, imagine trying to specify directions on how to get somewhere. By the end of the article you’ll understand how the Groovy code in Listing 1 works even though to looks almost like plain English sentences.

    Listing 1: A DSL for giving Directions

    The Canvas

    We’ll use the same running example through all of the exercises. So let’s start by painting out a few primitive ideas. Think of these basic building blocks as the undercoat to our DSL canvas. Thinking about your domain is always a good place to start if you’re considering writing a DSL. Think, analyze, and compare the domain to see how it should be naturally organized. If you read the example in Listing 1, you may notice a few similarities between the different lines of code. There are actions, such as ‘stand’ and ‘ride’. There are vehicles, such as a ‘bus’ or a ‘tram’. And there are locations, such as the ‘bus stop’, ‘Basel’, and ‘Birsfelden’. We’ll model the actions as methods later, so let’s skip those for now. Vehicles and Locations are fairly straightforward, so we’ll model those as Java enums, as shown in Listing 2. I’ve put them in a package so that I can do a static import on them later.

    Listing 2: Modeling Locations and Vehicles

    There is also something else in common between all of the instructions from Listing 1. They all have a duration or distance, such as ’7 minutes’ or ’10 stops’. A duration is a little bit harder to model, but not much so. For sake of simplicity, we’ll just define a Duration class that represents either a unit of time or a unit of distance, as shown in Listing 3. I applied the TupleConstructor annotation to generate a set of constructors on the object, making it a little easier to work with.

    Listing 3: Modeling a Duration

    The last bit of undercoat to apply to our canvas is the Instruction object itself. Listing 1 creates a list of Instructions behind the scenes, so we’ll need to model those as well. Similar to Duration, it’s a simple data type with a few properties and is shown in Listing 4.

    Listing 4: Modeling an Instruction

    An Instruction has an action (stand or ride), a location (bus stop or Basel), a duration (five minutes or three stops), and optionally a vehicle (a bus or a tram). Now that the undercoat is applied, let’s look at some different ways to construct these Instruction objects.

    Cave Paintings

    The most primitive way to create Instructions is to call the constructors of objects directly. This is hardly a DSL but at least it is an improvement over the Java equivalent. There’s not much here to be proud of, and list literals like [] and the leftShift operator to add list elements is only a slight improvement over the alternative. At least Listing 5 is rather short.

    Listing 5: Creating Instructions Explicitly

    The problems with this code sample is that there is a lot of accidental complexity: pieces of the underlying programming language bleed through and obscure the intent. In the first instance, only the words ‘stand bustop 5 minutes’ are essential to the problem of creating instructions. The other 59 of the 79 characters are non-essential complexity. A 25% signal to noise ratio is pretty poor. The classical solution to this problem (in a sense that it can be applied to Java code as well) is to create a fluent interface around Instruction objects so that the end user is shielded from these implementation details.

    Classicism

    A fluent interface is a way to chain method calls together in order to eliminate a lot of the noise associated with configuring data. Fluent interfaces can be created with statically compiled languages as well (like Java) and requires no special metaprogramming facilities in the host language. The trick is to be creative with method return types. Listing 6 shows the result of improving our signal to noise ration after refactoring to a fluent interface.

    Listing 6: A Fluent Interface for Instructions

    This is a big improvement and raises or signal to noise ratio from 25% all the way up to 75%. The only noise left in this example is the parenthesis party nestled between all the interesting bits. Hmmm, looks like someone invited a few periods along as well. We’ll do better in the next example, but let’s look at how to implement this fluent interface first.

    As I said, the trick is to be creative with return types. For example, the code ‘minutes(5)’ actually instantiates a Duration object for us (Listing 7), which is then passed into the ‘stand’ method as an argument.

    Listing 7: A minutes Method

    The trick is to make all of the method calls chain together. So the ‘stand’ method needs to return something that has an ‘at’ method on it, and that in turn needs to accept a Location parameter and create the actual Instruction. Technically speaking, stand is a higher-order function: it is a method that returns to you a method. Groovy’s dynamic typing and map-implemented interfaces make this a pretty simple task, as shown in Listing 8.

    Listing 8: The stand Method returns another Method

    In Groovy, an object can be created as a Map literal using the [key: value] syntax. If the keys are Strings and the values or Closures, then that object can be treated as an object and have methods invoked on it, which is what Listing 8 shows.

    At first, fluent interfaces often seem complex to implement. But after writing one or two you’ll often find it is really not too difficult. You have to think differently about how you craft an API, but in the end you can get a lot of usage and nice APIs using a fluent interface instead of metaprogramming. Let’s turn now towards bouncing some of those pesky parentheses out of the party using a little Groovy metaClass magic.

    Impressionism

    In our tour of DSL art, I’m calling the next technique impressionism. Like impressionist paintings, it does a slightly better job of capturing the intent than the previous example, but if you examine it closely it doesn’t seem to be much clearer than the alternatives. The motivating code is in Listing 9, can you spot the difference?

    Listing 9: Five Minutes not Minutes Five

    There are two less parentheses, but an added period. ‘minutes(5)’ became ’5.minutes’. The signal to noise ratio improvement is marginal; the advantage here is that the code more closely resembles the away we speak. Nobody sticks their head over the cube wall at 12:05 and asks, “Do you want to go to lunch in minutes 5?” Instead, they say “5 minutes”, which is exactly what this code says. This is a small change to implement, and listing 10 shows that making the language support singular and plural words is just a few lines of code.

    Listing 10: Metaprogramming the Duration

    What’s happening here is that we’re adding a method called ‘minutes’ and ‘minute’ onto the Integer class, and this method is creating the Duration object for us. Other than replacing the old ‘minutes()’ method with these four lines of code, there is no change to the previous example. The code all just stays the same.

    The combination of fluent interface and metaprogramming is powerful. Sure, there are some issues with periods and parentheses, but overall it is a pretty big improvement over trying to call constructors and wire objects together in Java. Groovy 1.8 takes things a little bit further and leaves us with the best example yet.

    Expressionism

    The last example is the best. It contains a minimum of accidental complexity and Groovy bleed-through and looks almost like the English language equivalent. For fun, I encourage you to compare Listing 11 with the cave paintings listing in Listing 5. It’s quite a bit improved.

    Listing 11: Command Expressions

    I call this final version Expressionism, not because it relates very well to the 20th century art movement of the same name, but because it uses a new feature called Command Expressions and is the most expressive of all the examples.

    So what are the code changes? You might notice that there are no more listings in this article. That’s right, command expressions are just the way code may be written now. Listing 11 showing the command expression usage and Listing 9 without the usage are functionally equivalent. ‘Stand’ and ‘ride’ are still method calls that return the ‘at’ and ‘on’ methods. As long as the code follows the follows the pattern ‘method parameter method parameter method parameter’ then it gets converted into ‘method(parameter).method(parameter).method(parameter)’. You can chain as many together as you like; Groovy won’t complain. The result is a nice readable chain of expressions without any additional effort. At the time being, Command Expressions are the state of the art when it comes to DSLs in Groovy.

    Art Criticism

    There are a couple of pitfalls to be wary of. Command expressions are shown here in the best possible light in order to display their power. In reality, they are also a little fragile. Any code not following the ‘method parameter method parameter’ rhythm doesn’t easily fit into the command expression pattern. The result is that you might have to twist your words a little to make them fit into this pattern, which moves it away from natural language and towards accidental complexity. Also, there is always the Groovy grammar and keywords to look out for. For instance ‘for’, ‘native’, and other keywords cannot appear in your DSL, a problem which other languages do have solutions for.

    Also, it is probably best to avoid command expressions outside of DSLs. The code ‘list.collect{ … } each { … }’ looks like a syntax error to most Groovy programmers because there is a period missing before the each method call. However, it isn’t wrong and works just fine. Confusing, but correctly functioning. Currently, Groovy programmers are used to some parentheses and periods, and it’s confusing to leave them out unless you have good reason.

    Create Your Own Art

    Thus concludes the tour of the state of the art with Groovy DSLs. To start, Groovy fluent interfaces are a great way to organize an API and make it easy to use. While not a true domain specific language, in a low ceremony language like Groovy they can go a long way towards increased expressiveness and better signal to noise ration without resorting to programming trickery. For more power, start to use metaprogramming to fine tune the the exact API you need, and use Groovy Command Expressions when you need them. How go forth and make your next DSL a true work of art.

    Need help with Groovy? Canoo is ready to tackle any challenge. Contact info@canoo.com to learn more about Groovy Training and Consulting.

    Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
    • DZone
    • Y!GG
    • Webnews
    • Digg
    • del.icio.us
    • DotNetKicks
    • Facebook
    • Google Bookmarks
    • Newsrider
    • Twitter
    • YahooBuzz

    1 Comment »

    1. john said,

      October 7, 2013 @ 3:12

      I’m a Grails developer for 4 years already, but just barely scratches the tip of groovy. Hopefully I find time to explore DSL soon.

    RSS feed for comments on this post

    Leave a Comment


    six + 4 =

    css.php