Groovy, Eclipse Commands and Expressions
During my last project I had the dubious joy to work with a boatload of command framework expressions (activeWhen
, enabledWhen
). I appreciate the need for such a framework… don’t go through the overhead of loading all the classes for dozens of plugins to determine which commands are available… and instead use a lightweight alternative inside the plugin.xml file. This neatly sidesteps all the osgi class loading runtime overhead, making the eclipse experience fast and snappy. And I have to admit I am a sucker for speed. So I am on board with the concept but how things work in practice aren’t optimal in my opinion.
I’m not a big fan of XML in general and the idea of writing code in XML gives me the shivers. I have written enough XSLT to know pain… in copious amounts. We already have a long-established notation for formal expressions: programming languages. There is a very good reason Java’s syntax (or that of any other popular programming language) looks nothing like XML.
One argument that proponents of XML often make is that you usually shouldn’t have to look at XML at all. Well, I think they are wrong. The XML leaks through the cracks way too often. As a developer I am probably more exposed to that than the average user but nevertheless I still have to put up with it. Sometimes there may be a layer of GUI eye candy in between, but for something as specific as an expression editor… the standard extension editor just doesn’t cut it for me.
With a quick look at the following image: Tell me when the expression is true. Oh right, you can’t - the expression is distributed over several tree nodes.
Classic expressions
Now let’s look at the XML. Only slightly better, but at least you can see everything at once. Still clocking in at 6 elements, the signal to noise ratio is abysmally low.
To put my money code where my mouth is… so I tried to implement a more elegant solution to the problem. Note though that this is just a proof of concept hacked together in my spare time. I wanted to integrate a scripting language with the command framework so that expressions could be written as small snippets of code. The ecosystem of scripting languages is quite prolific at the moment, so there is a lot of choice. But choice is good right? I settled for Groovy since I had done some embedding experiments with it before. But I am convinced that other scripting languages would work just as well.
Hooking up the groovy runtime was a snap, adding another expression type (creatively named “groovy”) was easy as well. I found out before long that I had to specify which command variables to use. The first reason for that was that I had to bind these command variables to groovy variables - although this could also have been achieved with some propertyMissing trickery. The more compelling reason was that the command framework had to known when to re-evaluate the expression, i.e. when relevant variables had changed. The resulting expression now looks like this:
activePartId != "groovy.expressions.navigationView" || selection.size() == 2
Quite a bit more readable, eh? Notice the “using” attribute specifying the used variables mentioned above. It might even be possible to compute these variables by traversing the syntax tree of the expression. This feature is offered by some scripting engines and would mean we could completely drop the “using” attribute. The rest is just plain groovy code, and I’m sure most of you will have no problem understanding an expression like that.
Next I want to discuss some of the caveats and advantages of this approach.
Caveats
Needs a scripting engine As far as I know, Java 1.6 ships with a Rhino interpreter so that could be an option for the future. Other small scripting engines (e.g. BeanShell) could be integrated as well. That is unless the big bad licensing monster rears its ugly head.
Might need standardization As mentioned above there is a whole plethora of scripting languages available right now on the JVM, so choosing “the one” might be a problem. Another option of course would be to delegate to JSR 223 and let the user decide.
Yet another language? There might some developer resistance concerning yet another language to learn. While this is certainly a concern, some scripting options are very close Java (Groovy and particularly BeanShell come to mind). I would argue that the current XML expression language is “yet another language” to learn as well - and a cumbersome and ill-specified one at that.
Advantages
Legible expressions As mentioned above, the expression is much easier to parse for developers. The machine doesn’t care either way, but software should not only be list of machine-operable instructions but also as a means of documentation and communication. The current implementation falls way short in that regard.
Debuggable Ever tried to debug a highly nested XML expression? Not fun, let me tell you. With “scripted” expressions in the worst case you can pepper your code with println statements. In the best case you can set breakpoints on your expression code editor. The latter would probably be quite a bit of work but I don’t think it is totally infeasible.
More powerful I haven’t looked into it too deeply but the current expression engine is probably a turing tarpit eager for prey. A “proper” scripting language would gives us a well understood, turing-complete way to describe complex expressions. It would also make it easier to factor common functionality into shared functions in order to reduce coupling and repetition.
Improved Testability A scripting environment might also make it easier to write and execute unit tests on the expression to verify its correctness. While this also possible with the current expression engine, it is quite a bit of work to get up and running. With scripted expressions one could fairly easily set up the variables and run a minimal execution wrapper around the expression code to test its behaviour in a classical JUnit test.
I put up the code on the github. Basically the application is your vanilla RCP Mail example. The meat of the code is in org.eclipse.core.internal.expressions.GroovyExpression
. Apart from the mucking in the expression engine, the only thing I did was add two commands and handlers with the same activeWhen semantics, but once described as classic XML and once expressed as Groovy code. Have a look, I’m looking forward to your comments and critique.