How to inherit docstrings for fronted fns?

Often we make an API ns that serves to alias various functions from other namespaces so that another namespace (e.g. routes) can stay clean of the abundance of :require s. Is there a way to do this while keeping the docstring from the original fn, for tooling purposes?

Example:

;; in "sources"
(defn sources-summary
  "Get all sources with their info.

  [{:source-name \"wsj\"
    :id xyz
    :material-quantity 42
    :complete-percent 80
  }] "
  []
;; implementation
  )

;; in the API NS. How should I keep the docstring?
(def get-sources sources/sources-summary)

You can use the var metadata:

$ clj
Clojure 1.10.1
user=> (defn foo "foo" [])
#'user/foo
user=> (defn ^{:doc (:doc (meta #'foo))} bar [])
#'user/bar
user=> (doc bar)
-------------------------
user/bar
([])
  foo
nil
1 Like
(defn update-alias-meta [old-name old-meta]
  (fn [new-meta]
    (merge new-meta
      (update old-meta :doc #(str "Alias for " old-name "." (if % "\n\n") %)))))

(defmacro defalias [new-name old-name]
  `(alter-meta!
    (def ~new-name)
      (update-alias-meta '~old-name (meta (var ~old-name)))))

(defmacro defaliases [& syms]
  `(do
    ~@(map
       (fn [[new-name old-name]]
         `(defalias ~new-name ~old-name))
       (partition 2 syms))))

Usage:

(defalias plus +)
(doc plus)
-------------------------
clojure.core/+
([] [x] [x y] [x y & more])
  Alias for +.

Returns the sum of nums. (+) returns 0. Does not auto-promote
  longs, will throw on overflow. See also: +'

I don’t recommend abusing these. I find it very useful to be able to just look at a namespace form or a function and know what it depends on, and aliases make that more difficult.

I don’t think I’m actually using these in any of my code. I originally wrote them when I was using CouchDB and was making a library to provide more functionality than clutch, but I didn’t want to have to require both my library and clutch in every namespace (and remember which function belongs to which). Other than that, I have never found the loss of clarity to be worth saving a few lines of typing.

3 Likes

Btw, take a look at https://github.com/ztellman/potemkin which is a widely used library to accomplish this task.

3 Likes

Ah! Thanks. It took me a minute to find the capability in question since it’s not in the readme. For anyone interested, it’s import-fn: https://github.com/ztellman/potemkin/blob/e8c64802b8772a90110434d1b515ce35b78b961b/src/potemkin/namespaces.clj#L11

Addressing the abuse of them, I guess the API idea came to mind after seeing it implemented in many good libraries, such as tick api and others

This is the macro most people use:

It will call import-fn or import-macro for you.

Has anyone used import-vars in the context of clojurescript?
I’m trying to get some vars (macros and functions) in one namespace to be exposed in another where the consuming namespace is in clojurescript.

Or any strategy for creating aliases in clojurescript, with the docstring of the target var copied over also.

You’d think there’s no reason it shouldn’t be compatible with cljs since it’s all pure-clojure functionality, but I see that Potemkin is all written in clj and not cljc, so looks like it might not work for you

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.