Object Commando languages, development and design


Design By Contract with Clojure

I just learned about the design by contract features of Clojure, and I'm impressed by the simplicity. It's implemented using regular Clojure metadata (i.e. no new language constructs to support this). {Small correction to this previous statement. It looks like metadata, and can be read as metadata, but is actually compiled into the function (i.e. can't be modified at runtime). Thanks for the correction Alex.} Several times I desired DbC in Java and have tried some of the libraries written for Java. The Java ones were generally built on comments or annotations. Bottom line is that they just didn't feel like they seamlessly integrated into the language, and they seemed to have a short shelf life. By short shelf life, I mean there were a lot of proof of concepts and abandoned projects, but none that were viable over the long term.

DbC in Clojure

Pretty slick how it's implemented in Clojure. First we take a normal function definition;

(defn pos-add [& args]
(apply + args))

It doesn't really do anything interesting, just delegates to the plus operator, but should only be used for positive integers. If you've not seen the & symbol, it just collects all function arguments in as a sequence. So a precondition of this function is that all arguments passed into pos-add should be zero or greater. To add this, the code looks like:

(defn pos-add [& args]
{:pre [(not-any? neg? args)]
:post [(<= 0 %)]}
(apply + args))

So there are two new pieces, a :pre that takes expressions, all of the expressions must return true for the pre-condition to pass. In the example above, there is only one expression, and it ensures that there are not-any negative numbers in the argument parameters. It also insures the the result is 0 or greater. The post condition isn't of much value here, but I added it to demonstrate where it would go. Calling the function is the same as calling any other function, but if the pre/post conditions are not met, an AssertionError is thrown. Below are some basic tests for the function:

(is (= 10 (pos-add 1 2 3 4)))
(is (zero? (pos-add 0 0 0 0)))
(is (= 5 (pos-add 1 1 2 1)))
(is (thrown? AssertionError (pos-add 1 2 3 -4)))

What led me to Clojure's DbC features was reading On Clojure and there was a proposal for a new DbC syntax. I like DbC in the original style, but I think that the one at On Clojure has some additional benefits because it can provide some hints as to what types are expected in the function. If you read Smalltalk Best Practice Patterns by Kent Beck, he recommends to name the variables after the type that is expected. So if the method is findByName, the parameter would be aString to give the caller a hint as to what is expected. What was detailed in the On Clojure blog not only provided hints about the type but also would also let you know acceptable values just by looking at the function declaration and the accepted parameters.

I would like to see the pre/post condition information somehow worked into the documentation generated by Clojure. Seems like it would be a very useful feature for callers of APIs.

Filed under: Clojure, Languages 2 Comments

Emacs Talk at Lambda Lounge

I'm giving a talk tomorrow at the Lambda Lounge on Emacs. I'm planning on spending about half the talk on some Emacs conceptual basics. When it comes to the basics I'm going to try and avoid the "this key does this" and "that key does that". I think going over cursor movements etc will just be lost. If you're truely new to Emacs, you'll need to go through the Emacs Tutorial (which comes with Emacs, there's a link to it on startup) to get the basic movements down. Instead I'm planning to go over the concepts of buffers in Emacs, the modeline, the minibuffer, the .emacs file etc. I'm also planning on spending a decent amount of time going over the help system, both the info system and the built-in Elisp documentation. Then I'm planning on going over some Emacs Lisp basics, Eshell, org-mode and a little on Dired. Then I'm planning on doing some development demos, specifically highlighting REPL environment integration into Emacs with SLIME, Tuareg Mode and maybe some Ruby.

Filed under: Languages No Comments