Stathis Sideris — Blog

published: 04 Mar 2012

Self-explanatory code

In most database systems, there is the EXPLAIN command, which when given a query, it will tell you how the database system will execute the query. This provides you with the query plan, which tells you which indices will be looked up in the database, and other possibly non-obvious performance tuning that might happen to your query. I was always fascinated with EXPLAIN, because it is a bit unusual in the sense that it's a piece of code that takes another piece of code as its parameter, looks at it, and tells you what it will do. The self-referential nature of this made it exciting.

For a bit less than a year now, I have been developing the Clarity library, which can be used to develop GUIs in clojure. It's been a very interesting experience, and the library is getting to the point where it can automate useful GUI tasks, like styling a hierarchy of Swing components using a pre-defined stylesheet. This kind of automation can feel a bit magical to the developer, because they may not be familiar with the exact semantics of stylesheets. In order to make development with Clarity a bit easier (and to scratch my itch), I have introduced the explain macro in the clarity.dev namespace.

Currently the explain macro only supports explaining what will happen when a stylesheet is applied to a hierarchy of components. Let's look at a working example:

(ns testing
  (:use clarity.make
        clarity.style
        clarity.dev))

;;a stylesheets that makes all buttons' backgrounds red
(defstylesheet the-style
   (style (type :button)
      (:background (color :red))))

;;a panel with just 2 buttons
(def panel
   (make :panel (:id panel)
     (.add (make :button "Test" (:id button1)))
     (.add (make :button "Test 2" (:id button2))))

Now, you can ask Clarity to explain what will happen when the-style is applied to panel. In the REPL:

> (explain (apply-stylesheet panel the-style))

...and you get:

--- Showing matches only ---
1 out of 1 styles match

---

Style: (type :button)
Mutator:
  (:background (color :red))
Matches (2):
  $panel/$button1
  $panel/$button2

If your components did not have an ID nor a category, the output of the matches would look slightly less attractive, but it would still be readable.

By default, explain will show you only the styles that match at least one component in your component hierarchy, but you can make it show all styles, or only the ones that will not match at all:

;;show everything
> (explain (apply-stylesheet panel the-style) :show :all)

;;show not matched
> (explain (apply-stylesheet panel the-style) :show :not-matched)

explain ony covers stylesheets for the time being. I'm planning to extend its functionality as appropriate. Clojure being a Lisp makes the development of such "meta" functionality very enjoyable and you end up with developer-friendly software.

blog comments powered by Disqus