Question

I have namespaces foo and bar. Both have function hello.

I'm trying to write a function that calls either foo/hello or bar/hello based on a parameter. In other words:

(defn say-hello [target-namespace]
  (if (= target-namespace "foo")
    (foo/hello)
    (bar/hello)

Something like that, except that imagine there are 15 namespaces, so a simple if-else wouldn't suffice. It would be better to somehow leverage target-namespace and figure out the function to call from that. Is there a good way to do this?

Was it helpful?

Solution

You can use intern to get or create a var in another namespace.

 (intern ns name)
 (intern ns name val)

Finds or creates a var named by the symbol name in the namespace ns (which can be a symbol or a namespace), setting its root binding to val if supplied. The namespace must exist. The var will adopt any metadata from the name symbol. Returns the var.

So you could theoretically make your function do this:

(defn say-hello [target-namespace]
   ((intern target-namespace 'hello)))

However, this would be a very unusual thing to do in Clojure/ClojureScript and you can probably solve your problem more idiomatically using one of the polymorphism options such as protocols or multimethods. Protocols can handle most use cases, and is probably your best starting point (especially if you're coming from Java - they're very interface-like).

Syntax is like this:

(defprotocol Friendly
    (say-hello [this]))

And you can create a number of datatypes that conforms to the protocol using defrecord.

(defrecord person [name]
    Friendly
    (say-hello [this] (println (format "Hi, I'm %s" name)))

(defrecord dog [name]
    Friendly
    (say-hello [this] (println (format "Woof, Woof! I'm %s" name)))

(say-hello (Person. "Bob"))
;=> "Hi, I'm Bob"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top