Search code examples
clojure

Why is the class of '@foo Cons rather than PersistentList when inside a def?


A quick experiment under Clojure repl:

> (class '@foo)
clojure.lang.PersistentList

This is more or less expected, so let's wrap the same expression in a def:

> (def x '@foo)
> (class x)
clojure.lang.Cons

I tried playing with def and various other forms but '@foo seems to be the only one that triggers this behavior.


Solution

  • I tried this in a fresh REPL and reproduced the behavior.

    There is a convoluted explanation for the specific behavior you are seeing. You have uncovered a peculiar corner in the Clojure reader.

    The @ character is a "reader macro" that is shorthand for the following:

    @xxx  =>  (deref xxx)
    

    The ' character is another reader macro that is also shorthand for:

    'yyy  => (quote yyy)
    

    Put them together and you get

    '@zzz  =>  (quote (deref zzz))
    

    So the quote special form comes first. It says, "treat everything enclosed here as a data structure, not as executable code".

    The data structure (deref zzz) is a list containing 2 symbols, deref and zzz.


    With regards to the difference in the class between a literal and a Var, we see:

    user=> (def bbb '@foo)
    #'user/bbb
    user=> (class bbb)
    clojure.lang.Cons
    
    user=> (def ccc (quote (deref foo)))
    #'user/ccc
    user=> (class ccc)
    clojure.lang.PersistentList
    

    Using "object oriented" lingo, a Cons, PersistentList, PersistentVector, and LazySeq are all "subclasses" of the generic "Seq" type in Clojure. They can all be used interchangably, and the unexpected difference in the 2 classes above is an unimportant implementation detail.