When Scala DSLs Fail

logoThe hot new contender in the space of interal DSLs (domain-specific languages as libraries) is Scala. Scala is, as is implied by its name, a language that is designed to scale from small one-off scripts to large enterprise applications. It is a statically typed language, and in many ways can be seen as a successor to Java. It also compiles to JVM bytecode. Similar to Ruby, Scala has a flexible syntax, which makes it an interesting choice to develop internal DSLs for (like Ruby on Rails).

The most popular web application framework for Scala is Lift. On its website it is described as follows:

Lift is an expressive and elegant framework for writing web applications. Lift stresses the importance of security, maintainability, scalability and performance, while allowing for high levels of developer productivity.

In Lift, more configuration is done in Scala code rather than in XML files like in a framework like Seam. Consequently, simple typing mistakes are typically caught by the compiler. One area where mistakes are still easily made are in its XML-based language for constructing user interfaces. I won’t milk this one too much, we know the trick by now, but let me demonstrate what happens when a programmer makes mistakes in templates.

Mistake #1: mistyping a class name

What happens if my satanistic fingers force me to type hellWorld, instead of helloWorld:

<lift:surround with="default" at="content">
   <h2>Welcome to your project!</h2>
   <p><lift:hellWorld.howdy /></p>
</lift:surround>

We get no error at compile time. At runtime, however something odd happens.

lift-fail-1

It does display the "Welcome to your project!" message, and the list item with "Home" on it is part of our global template. But where did our howdy message go?

In the console we see the following;

lift-fail-1b

In a way this is an acceptable message, but shouldn’t this be an error?

Mistake #2: mistyping an opening tag

This is a nice one. Instead of typing "surround" in our template, we misspell it as "surrond". A honest mistake. How does Lift deal with this?

<lift:surrond with="default" at="content">
  <h2>Welcome to your project!</h2>
  <p><lift:hellWorld.howdy /></p>
</lift:surround>

This is what we see when we load the page:

lift-fail-2

line 4 does not exist? I’m pretty sure that it does… Looking at the stacktrace, I see it has to do something with XML parsing, but other than that, the message is kind of unexpected.

Alright, one more, then it’s been enough.

Mistake #3: mistyping a template block name

Let’s now misspell some more, we’re getting good at it.

<lift:surround with="default" at="conent">
   <h2>Welcome to your project!</h2>
   <p><lift:hellWorld.howdy /></p>
</lift:surround>

Again, no compilation errors. When we load the page we see the following:

lift-fail-3

No error message on screen, or in our console. What happened here? We only see the global template and nothing from the content we just defined. This, of course, has to do with the fact that we’re defining a template that’s never actually called. It’s subtle, but can be tricky to find.

Enough already, we get it!

Ok, ok. I know. You get my point. Statically typed framework fail to detect errors that are encoded in strings and XML files. So what can we do to fix this (other than IDE support)? Well, the obvious thing is stop abusing strings and XML files in this way. If we find an acceptable way to encode these things in Scala we can check a lot more. Lift takes its first steps towards this by doing configuration in its Boot class. There are a few Scala DSLs that make database queries statically verifiable. Still, the user interface part breaks. 

To fix this I attempted to build a simple version of WebDSL as an internal DSL in Scala. What follows is a piece of code that defines a user interface using this DSL:

scala-internal-fail-1

This piece of code defines an entries template. The template renders a header saying "All entries". Underneath we see a list of all Entry objects (Entry.all). For each entry there is a list item with a form. The entry’s name and text are displayed and there’s a button to delete the entry from the database. Simple and elegant (in my opinion).

The nice thing is that when I misspell one of the UI constructs, I get an error:

scala-internal-fail-2

So the error is found at compile time, which is nice. However, are these errors very helpful?

scala-internal-fail-2b

value buton? Is a buton supposed to be a value? In our domain-speak we’re attempting to define a page element here, not a value. The good thing about error messages as you compile is that you see that something is wrong early, and typically can see clearly where the error is. The error messages, however, are not always very helpful, and hardly ever domain specific ("No such page element: buton" would have been a great error message).

But there’s another error in the code I just showed and the compiler didn’t catch it at all. The thing is that listitems cannot appear just anywhere, they have to appear within lists! The list construct was left out. That’s easily fixed:

scala-internal-fail-1-fixed

What this example shows is that although we can catch many errors by creating an embedded DSL in Scala, there are definitely limits. Additionally, there is no way to give domain specific error messages at compile time (unless we extend the compiler), error messages typically expose the underlying implementation. Yes I admit it, the code to construct a button and define its logic is actually a method call.

So although internal DSLs in a statically typed language help you to find certain types of error faster, the error reporting is far from perfect. This is one of the strong points of external DSLs as we will see in a future post. Update: This post, to be exact.

Tags: ,

  • nuttycom
    The complaint about typos in Lift templates is legitimate, but I think that it's important to recognize that the templates are *simply XHTML* and thus are good candidates for manipulation in an HTML editor. Your suggestion of an internal DSL for this purpose would make the templates inaccessible to designers.

    That being said, a static verification tool for Lift templates would be a great feature. At present, some of this can be done with unit tests, but a nice dsl to simplify the construction of such tests is a great idea!
  • It should be possible to create a type-safe builder pattern, which only allows a listitem to appear within a list- that's where Scala actually shines.
  • I have been thinking about that, but I'm afraid control structures like for loops and if statements won't work anymore, or am I wrong?
  • Mistake 2 is easily caught by an XML editor/checker. 1 and 2 won't be without extra work (e.g., parsing out the component names and some schema/schematron hackery), but it's pretty doable. As long as you aren't synthesizing the XML programatically, then I think an XML based DSL can be close to an external DSL. The coordination problem is quite large, as is the debugging problem.
  • Lucian
    I think you're relying way too much on your compiler.

    Neither DSLs nor XML are a good base for templates. Text templates like Jinja2 are the most natural way to express a template (text with a bit of logic).
  • Ugh, jinja reminds me of JSP. Control structures in the template, no thanks!
  • Jules
    What is the font you're using for the Scala code? I like it.
  • From the screenshots you mean? It's Eclipse's default font on Mac: Monaco. And the Scala plugin-in's default color scheme on Eclipse.
  • Jules
    Thanks. I can't get it to look that good on either Linux or Windows, unfortunately...
  • Jules
    Actually, I'd like to know which color scheme that is too :)
blog comments powered by Disqus