5
votes

I have some private functions in one namespace that I would like to include in a second namespace. e.g.

(ns one)

(defn ^:private foo 
  "A docstring"
  [x] (* x 2))

And the second namespace needs to create an alias to this:

(ns two)

(def foo ???)

(foo 3)   ;; should work as if the function in namespace one was called
=> 6

Ideally I'd like to preserve the docstring so I don't have to maintain it in two places. Also I'd like to have the option to either use the same name or a different name.

The reason for this requirement is as follows: the functionality is needed/used in namespace one. one is a dependency of two, and since we can't have circular dependencies it won't work to define foo within two itself. two is the public API, so foo needs to be publicly part of the two namespace.

What's the best way to achieve this?

2
You want the alias name to be same or it can be anything? - Ankur
@Ankur - currently looking to use the same name, but in some cases it might also be useful to create an alias with a different name so it would be great if the solution allowed that. - mikera
Try this: (def foo (with-meta one/foo (meta #'one/foo))) - Ankur
Which begs the questions: Why is foo in one? And why is it private? Obviously it should be in two and public... - kotarak
@kotarak - good question, have added the explanation in the question, but basically it's because two is the public API. - mikera

2 Answers

5
votes

How about this:

(ns one)

(defn- foo 
  "A docstring"
  [x] (* x 2))

(ns two)

(def foo-alias #'one/foo)
(alter-meta! #'foo-alias merge (select-keys (meta #'one/foo) [:doc :arglists]))

The trick is to not resolve the symbol 'one/foo, hence avoiding to trigger the private flag on its metadata. Then after aliasing foo in your second namespace, you simply cherry pick the metadata you want to keep from the previous definition.

0
votes

The Potemkin library has a function import-vars for this kind of thing.

https://github.com/ztellman/potemkin