Having read Tim Bray’s tips for Clojure newbies from a newbie, I decided to write a version of my own.

First, I generally agree with Tim’s observations, so this post is more like minor extension. In fact I recommend reading Tim’s version first.

My background so that you know my point of view: Added to Java, C and Python experience I have lots of exposure to Prolog (which is, like Clojure, homoiconic) and some experience with OCaml (a functional language). I have had some practical contact with other “modern languages over JVM”: Scala and Groovy. No Lisp experience (other than basic elisp).

Reading suggestions: Other than Tim’s comments I would add: The clojure site information is really not very useful as a starting point, the reference part assumes that you already know quite a bit and it is though on newbies, the only thing that I tend to use is the API section. Like Tim, I also use Mark Volkmann’s introduction (It is my main documentation, and I would be a bit more positive than Tim about it. For an intro article it is great. I strongly recommend it as a starting point and as the reading anchor during the first weeks). Next week I plan to order Stuart Halloway’s book, so I still cannot comment on that.

On a more general note, while learning Clojure, I’ve found Paul Graham’s On Lisp (available for free), a gem and I would strongly recommend it. It is not an easy read, it probably takes months to digest the content. But it is really a great book.

Clojure is a fast moving target. Documentation of many modules and functions might not be up to date with the current code. I have noticed that sometimes the best “documentation” ends up being reading the code (clojure is hosted on github and so are many satellite projects – In fact getting familiar with github is probably another recommendation).

Some of the contrib stuff is a bit too green, and I would recommend inspection of some of the modules before using them. Just because it is accepted on clojure.contrib it does not mean it is production quality, has even bare functionality or the exposed API is stable. As an example the graph API is minimal and I question if the graph structure directed-graph is enough to represent a general directed graph (future changes to it will probably break existing code built on top of it). This is not a criticism, a new product is bound to be fast changing, and agile methods of development will entail lots of instability at the beginning. But a caveat should be added to the stability and completeness of parts of clojure-contrib.

Regarding editors and IDEs, I would probably recommend for you to stick with what you feel more comfortable with (vi, emacs, netbeans, eclipse, …). Note that Clojure, being a Lisp derivative has a big share of its user base on emacs. I mainly use Netbeans using the wonderful enclojure plug-in. I can only say that encloure is stable enough for usage and I recommend it if you are a Netbeans type of person.

I also second Tim’s comments on namespace hell. Uses/imports/requires can be quite confusing. Hell is too harsh of a word, but purgatory seems an accurate description ;) . Also, as Tim says, the clojure mailing list and IRC channels are very, very helpful.

One of the most annoying kinds of bugs come from typing problems, things like this:

(defn hiddenBug [a b]
  (println a) ;lets do a println for debug purposes
  (println b) ;lets do a println for debug purposes
  (if-not (= a b) (println "they are different!"))
)

Now lets call this:

(hiddenBug 'x "x")
x
x
they are different!

Notice that, when you are debugging a and b will seem equal on a println, but they are not (one is a symbol, another a string)!

The biggest gotcha that I have been getting is the expectation (Java based) that stupid things raise exceptions, but sometimes they don’t. Here is an example:

user=> (contains? '(a b) 'a)
false
user=> (contains? 'blab 'a)
false
user=> (contains? (list 'a 'b) 'a)
false
user=> (contains? ['a 'b] 'a)
false
user=> (contains? '(a b) :a)
false
user=> (contains? '(:a b) :a)
false

In all these cases, the Java-expecting gnome inside me was hoping something of a throw (as the first argument is not of the type required by contains? ) . It is not clear to me if this is a design issue with contains? only, or it is something that is standard along the whole API. But I notice this from the API reference:

(even? n)
Returns true if n is even, throws an exception if n is not an integer

So it seems that the design is not homogeneous throughout the API as some functions throw exceptions. I would probably prefer a throw when the type of arguments is wrong, but people with lots of Lisp experience might have a different view on the issue. Anyway I would like to understand if the lack of homogeneity is a feature or a bug.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • Reddit
  • Technorati
  • LinkedIn
  • connotea
  • FriendFeed
  • Twitter

3 Comments

  1. Patrick Logan says:

    “hiddenbug” isn’t a problem. println isn’t guaranteed to print unequal values differently. Note the documentation for println and print says “for human consumption” – it is intended to be informative but not “readable” by a program to get the same value back.

    For “contains?” – yes, this is not the java method from the collections API. You can use that…

    (.contains ‘(:a a) ‘a) => true

    The documentation is accurate in that (contains? 1 2) is false but (even? ‘(:a a)) is an exception. Kind of makes sense as 1 does not contain 2 and it is non-sensical to say that (:a a) should be even or odd.

    Chalk it up to clojure is not java and you do have to dig beyond initial expectations as a java developer.

  2. Public Farley says:

    Actually the Contains? function is working as per spec. In retrospect it may have been better named as contains-key? though.

    Here’s why:

    Try the following

    (contains? ['a 'b] 0) => true
    (contains? ['a 'b] 2) => false

    (contains? {:1 ‘a :2 ‘b} :1) => true
    (contains? {:1 ‘a :2 ‘b} :3) => false

    Contains? performs the following test: “for a given collection does the given key exist?”. For the first two calls, since vectors are keyed by their indices, the second argument is an index. Hence, the indices 0 and 1 exist. The index 2 does not.

    Similarly for the map, the key :1 exists. The key :3 does not.

    For a list, there is no defined key so a test of the form (contains? key) always returns false. You do have a point in that it might have been better if an exception of something like KeyUndefinedForCollectionException was thrown…

    Sadly, for list membership, I have resorted to dropping down into the java contains method (using the dot operator) as follows:

    (.contains ‘(a b) ‘a) => true
    (.contains ‘(a b) ‘c) => false
    (.contains (list ‘a ‘b) ‘a) => true
    (.contains (list ‘a ‘b) ‘c) => false

    Yup. Kind of confusing…..

  3. tiago says:

    Public Farley: My feelings exactly.

Leave a Reply