When I try to run the following code from the REPL (playing with dynamic records):
(defrecord (symbol "rec2") (vec (map symbol ["f1" "f2"])))
I receive the error CompilerException java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:23)
I'm asking myself where I generate this PersistentList considering that:
user=> (symbol "rec2")
rec2
user=> (vec (map symbol ["f1" "f2"]))
[f1 f2]
But my real question is why the following code works:
user=> (defrecord rec2 [f1 f2])
user.rec2
I've also tried:
user=> (clojure.core/defrecord (clojure.core/symbol "rec1") (vec (clojure.core/map clojure.core/symbol ["f1" "f2"])))
CompilerException java.lang.RuntimeException: Can't refer to qualified var that doesn't exist, compiling:(NO_SOURCE_PATH:40)
(qualified var? The only difference is that I'm fully qualifying function names WHICH EXIST, BTW) Obviously I'm missing something in my understanding of Clojure defrecord macro, but I thought that macro are simply AST modifiers so if I give it a symbol or something that resolves to a symbol it's the same thing, so I would like someone to explain me why the normal form works and the others not!
TIA!
The problem is following: defrecord
is a macro and all arguments are not evaluated. They passed to macro, so it gets (symbol "rec2")
- list that contains 2 elements: symbol and string, not rec2
as you expect. You can try following:
(eval `(defrecord ~(symbol "rec2") ~(vec (map symbol ["f1" "f2"]))))
It creates list (defrecord rec2 [f1 f2])
and then evaluates it.
But I don't think that it's good idea to eval some code dynamically. May be there is some other way to do it.