Riveascore
Riveascore

Reputation: 1852

def'ine a value with a dynamic name

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

Upvotes: 3

Views: 68

Answers (2)

Matthias Benkard
Matthias Benkard

Reputation: 15759

The run-time equivalent of def is intern:

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

Upvotes: 1

DaoWen
DaoWen

Reputation: 33019

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}

Upvotes: 3

Related Questions