« back

Cryptic Clojure Errors - What Do They Mean?

09 Jan 2013

What the h**l is an ISeq and why can't it be created from: clojure.lang.Symbol and other explanations for understanding why your code is broken.

I am fairly new to clojure and I find that one of the things that I realized is slowing me down significantly are the errors. They are not very helpful if you do not have a rich understanding of the language. Today I want to take a look at some of the terms that I keep seeing in the errors and figure out what they mean so that I can have a better context of how to fix my code. I am finding that often times, we need to look to both clojure and java for explanations.

What is an ISeq?

Well, ISeq refers to sequence. A sequence in clojure is a logical list.

I keep seeing the I in all of my errors and Doug helped me clear that bit up. Using I in front of your class is convention in java when you are referring to an Interface. That led me to the question of, "Okay, well what is an interface"? I think the java documentation does a great job explaining it so let's take a look...

As you've already learned, objects define their interaction with the outside world through the methods that they expose. Methods form the object's interface with the outside world; the buttons on the front of your television set, for example, are the interface between you and the electrical wiring on the other side of its plastic casing. You press the "power" button to turn the television on and off. In its most common form, an interface is a group of related methods with empty bodies. A bicycle's behavior, if specified as an interface, might appear as follows: interface Bicycle { // wheel revolutions per minute void changeCadence(int newValue); void changeGear(int newValue); void speedUp(int increment); void applyBrakes(int decrement); } To implement this interface, the name of your class would change (to a particular brand of bicycle, for example, such as ACMEBicycle), and you'd use the implements keyword in the class declaration: class ACMEBicycle implements Bicycle { // remainder of this class // implemented as before } Implementing an interface allows a class to become more formal about the behavior it promises to provide. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler. If your class claims to implement an interface, all methods defined by that interface must appear in its source code before the class will successfully compile.

Okay, that makes a lot more sense now and understanding that plus the 'I' naming convention, we can look at our errors better and get to the heart of the issue. Now let's look at some of the other pieces.

clojure.lang.symbol - The clojure docs do a good job with that piece...

 1 01	;; Returns a symbol with the given namespace and name.
 2 02	;;
 3 03	;; (symbol name): name can be a string or a symbol.
 4 04	;;
 5 05	;; (symbol ns name): ns and name must both be strings.
 6 06	;;
 7 07	;; A symbol string begins with a non-numeric character and can contain
 8 08	;; alphanumeric characters and *, +, !, -, _, and ?.  (see
 9 09	;; http://clojure.org/reader for details).
10 10	;;
11 11	;; symbol does not validate input strings for ns and name, and may return
12 12	;; improper symbols with undefined behavior for non-conformant ns and
13 13	;; name.
14 14	 
15 15	user=> (symbol 'foo)
16 16	foo
17 17	 
18 18	user=> (symbol "foo")
19 19	foo
20 20	 
21 21	user=> (symbol "clojure.core" "foo")
22 22	clojure.core/foo
24 ;; some gotchas to be aware of:
25 03	user=> (symbol "user" 'abc)
26 04	ClassCastException clojure.lang.Symbol cannot be cast to java.lang.String  clojure.core/symbol (core.clj:523)
27 05	user=> (symbol *ns* "abc")
28 06	ClassCastException clojure.lang.Namespace cannot be cast to java.lang.String  clojure.core/symbol (core.clj:523)
29 07	user=> (symbol 'user "abc")
30 08	ClassCastException clojure.lang.Symbol cannot be cast to java.lang.String  clojure.core/symbol (core.clj:523)

From that we can realize that Don't know how to create ISeq from: clojure.lang.Symbol means that we have a symbol and we are trying to create a sequence from it.

Here is another one... java.lang.Long cannot be cast to clojure.lang.IFn

When you see java.lang., it is time to look directly at java. You can look directly at the java documentation. In this case long is basically a really large number. You use long when you need a number larger than int. IFn is actually referring to a function. Finally let's talk about cast. Cast means that we are trying to turn something into something else. So here they are trying to tell us that we can not take a long number and turn it into a function.

Here is another error. Parameter declaration let should be a vector - This error has to do with not including [] when you are declaring a function.

Let's talk about IPersistentCollection.I have seen this guy pop up a lot. Again, note the I(this is coming from an interface) I believe that IPersistentCollection actually refers to a group of "Collections" including Lists (IPersistentList), Vectors (IPersistentVector), Maps (IPersistentMap). Because collections support the seq function, all of the sequence functions can be used with any collection. Although this can help, it can still leave you unsure and digging in the docs. This page can tell you more specifics about each type of data structure and what you can an can not do with them.

These are most of the areas I have had confusion about. I will update this when I come across more of them. I hope this can help clear some things up for you like it did for me. Hopefully this will help save you some time and get you back to doing what you love... building things!

Happy error deciphering. :)

comments powered by Disqus