3

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 :)

Riveascore
  • 1,724
  • 4
  • 26
  • 46
  • 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](http://clojure.org/data_structures) for an alternative. –  Mar 25 '13 at 23:39
  • (The term "variable variables" is usually associated with PHP, but it is related to what it is being asked here.) –  Mar 25 '13 at 23:45

2 Answers2

3

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}
DaoWen
  • 32,589
  • 6
  • 74
  • 101
  • Hey, what I'm trying to do is create multiple agents with different names. I want to create say 6 agents that are of type "server" so each one will have name: server0 . . server5 – Riveascore Mar 26 '13 at 00:04
  • 1
    @FengHuo - If you just want to generate a bunch of "server" variables, why not just put them in a vector? I'll update my answer with an example. – DaoWen Mar 26 '13 at 00:09
1

The run-time equivalent of def is intern:

(intern *ns*
        (symbol (str "server" server-number))
        {:id server-number :value 4939})
Matthias Benkard
  • 15,497
  • 4
  • 39
  • 47