Injecting functions to a library

Hi,

what do you think is the idiomatic way to inject functions to a library. The library uses these functions internally, but these are so basic that I don’t want to pass them as arguments to the library functions. The application has to provide these functions once on startup. Then the library uses them.

An example:
Given a web application foo (cljs) and a server application bar (clj) which both use mylib (cljc). Both applications want mylib to use an application specific function to log warnings. Therefor these applications call (mylib/configure {:warn-fn warn}).

But how should mylib “store” the :warn-fn function? Using an atom seams overkill, since the value will never be changed.

Most of the libraries I work with that support some sort of setup register! or configure! type operation use atoms internally. I think it’s a reasonable choice. You can declare the internal state with a default value and it can be replaced or modified safely (atomically) via function calls.

2 Likes

You could add a multimethod to the library and then add :default implementations in the apps?

;; in cljc lib
(ns mylib)
(defmulti warn :please-provide-a-default)
(defn useful-fn-that-warns [] .... (warn "some xyz warning") ....)

;; in foo cljs app
(ns foo
  (:require [mylib]))
(defmethod mylib/warn :default [message] (println "logged by foo:" message))
(mylib/useful-fn-that-warns) ;; => logged by foo: some xyz warning

;; in bar clj app
(ns bar
  (:require [mylib]))
(defmethod mylib/warn :default [message] (println "logged by bar:" message))
(mylib/useful-fn-that-warns) ;; => logged by bar: some xyz warning

(Heavily edited from previous garbled attempt. 3rd time lucky?)

When I extended Specter to utilize a javascript-particular concern, it was made possible by their use of multimethods, which was good.

On the other hand, when I adjusted deja fu to work with a different time data type, it was by altering an atom.

So, I’ve appreciated either one!

I also think the atom approach is absolutely fine, and there’s really nothing overkill about it. However in your particular case why not just use reader conditionals?