Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(not= (type `(1)) (type `(1 2))) ;; Why? (single element list, syntax-quote, Cons, PersistentList)

Tags:

clojure

I see this behavior in Clojure 1.2.1:

user=> (type '(1 2))
clojure.lang.PersistentList
user=> (type `(1 2)) ;; notice syntax-quote
clojure.lang.Cons
user=> (type '(1))
clojure.lang.PersistentList
user=> (type `(1))
clojure.lang.PersistentList

I expected `(1) to be a Cons just like `(1 2) is.

I also tried:

user=> (type (cons 1 nil)) 
clojure.lang.PersistentList
user=> (type (cons 1 `()))
clojure.lang.Cons
user=> (type (cons 1 '()))
clojure.lang.Cons
user=> (type (cons 1 []))
clojure.lang.Cons

So what is the reason for `(1) and (cons 1 nil) to be PersistentLists?

like image 992
Łukasz Kożuchowski Avatar asked Mar 09 '12 15:03

Łukasz Kożuchowski


1 Answers

Like amalloy says, you shouldn't program against those exact types but against the seq abstraction.

However, I think I can take a guess at the reason. The Clojure forms that produce a PersistentList ultimately call RT.java, specifically the cons(Object x, Object coll) method. It begins with a pretty odd check: if(coll == null) return new PersistentList(x), after which it creates a Cons object if that check doesn't pass. If you look at earlier versions of the code, you can find this:

static public IPersistentCollection cons(Object x, IPersistentCollection y) {
    if(y == null)
        return new PersistentList(x);
    return y.cons(x);
}

So in an earlier version of the function, the call was dispatched to the cons method of the second argument, so the case when the second argument was null (i.e. nil in Clojure) needed special handling. Later versions don't do that dispatching (or actually do it but in a different way, presumably to support a larger variety of collection types), but the check has been retained since it does not break any correctly written code.

like image 108
Jouni K. Seppänen Avatar answered Dec 09 '22 03:12

Jouni K. Seppänen