3
votes

So I want to pass a function to the "name" portion of def. The problem is: "First argument to def must be a Symbol"

I'm trying to for instance do:

(def serverNumber 5)
(def (str "server" serverNumber) {:id serverNumber :value 4939})

But I can't find annnnnnny way to do this. Any help would be beyond appreciated :)

2
Using dynamic names (in most languages/scenarios) is often the wrong approach .. how would such a value be [uniformly] accessed later? See "Maps" in Clojure Data Structures for an alternative. - user166390
(The term "variable variables" is usually associated with PHP, but it is related to what it is being asked here.) - user166390

2 Answers

3
votes

First, I have to note that this seems like a bad idea. Why are you trying to generate defs with dynamically-generated names? (As @pst already pointed out, maps are the usual solution for creating bindings with dynamically-generated identifiers.)

Assuming you have a legit reason for doing this (maybe it's part of some library functionality where you're generating defs for the user), you can accomplish this with a macro:

(defmacro def' [sym-exp & other-args]
  `(def ~(-> sym-exp eval symbol) ~@other-args))

(def serverNumber 5)
(def' (str "server" serverNumber) {:id serverNumber :value 4939})

Note that this only works at the top level (since macros are run at compile time). If you want to do this in a function or something then you just need to use eval:

(defn def'' [sym-exp & other-args]
  (eval `(def ~(-> sym-exp eval symbol) ~@other-args)))

If you just want to create a bunch of agents, maybe something like this will work:

(def servers
  (vec (for [i (range 5)]
         {:id i :value 4939})))

Then you can just access them by index:

(servers 0)
; => {:id 0, :value 4939}
1
votes

The run-time equivalent of def is intern:

(intern *ns*
        (symbol (str "server" server-number))
        {:id server-number :value 4939})