Share your thoughts in the 2024 State of Clojure Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in Macros by

I am trying to do an exercise in Brave Clojure (chapter 8 exercise 3). I have simplified it to get to the bottom of my issue.

Consider this setup:

(def person {:first-name "Louis"
             :last-name "Bourvil"
             :age 32
             :city "Nantes"})

I'd like to be able to the following:

(create-func c-age :age)
(c-age person)

I know this works:

(defmacro create-func [func-name attr] `(def ~func-name ~attr))

But I was trying to do with a function and can't understand why this does not work:

(defmacro create-func [func-name attr] `(defn ~func-name [person] (~attr person)))
(create-func c-age :age)
; Syntax error macroexpanding clojure.core/defn at (REPL:1:1).
; user/person - failed: vector? at: [:fn-tail :arity-n :bodies :params] spec: 
:clojure.core.specs.alpha/param-list
; (user/person) - failed: Extra input at: [:fn-tail :arity-1 :params] spec: 
:clojure.core.specs.alpha/param-list

(from the repl)

Do you see where I'm wrong?

1 Answer

0 votes
by
selected by
 
Best answer
(defmacro create-func [func-name attr] `(defn ~func-name [person] (~attr person)))
(create-func c-age :age)

When you write this, it will expand to

(defn c-age [user/person] (:age user/person))
Syntax error macroexpanding clojure.core/defn at (/tmp/form-init14482279258588584188.clj:1:1).
user/person - failed: vector? at: [:fn-tail :arity-n :bodies :params] spec: :clojure.core.specs.alpha/param-list
(user/person) - failed: Extra input at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list

To avoid this, you should write

(defmacro create-func [func-name attr] `(defn ~func-name [person#] (~attr person#)))

or use another way to do not use qualified symbols in parameter name.

create macros for "getter" is a antipattern in clojure.
if you want to access a field, just access it.
also, def-macros usually can be written as a function

(def c-age (im-not-a-macro :age))
by
Indeed thanks so much! This is just an exercise from Brave clojure...
...