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

Viewed 76

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.

1 Answers

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.

Related