Abhinav Sarkar
Abhinav Sarkar

Reputation: 23792

How to set configuration parameters in clojure library?

I am writing a Clojure library and I am wondering what is the best practice for setting configuration parameters of a library.

Many libraries (like those in clojure-contrib) use global level parameter like *buffer-size* which the user can set by calling set! on them. But this does not seems to be best way to me as it creates a global state and there are chances of name collision.

The other way is to pass the parameters in every function call that is dependent on them. If there are many parameters then a map of them can be used instead of passing individual ones.

As an example, let's say that I am writing a cache library.

Using the first approach I have global parameters like *cache-size*, *expiry-time*, *cache-dir* etc. The user set!s these (or not and let them be default) and calls functions like (set-in-cache id obj) and (get-from-cache id).

Using the second approach, the user first create a map of parameters and passes it to every call

(def cache-parameters {:cache-size 1000 
                       :expiry-time: 1440 
                       :cache-dir "c:\\cache"})
(set-in-cache cache-parameters id obj)
(get-from-cache cache-parameters id)

So which way is the preferred way in Clojure and why?

Upvotes: 2

Views: 582

Answers (1)

Michał Marczyk
Michał Marczyk

Reputation: 84331

Actually you cannot set! things like c.c.io's *buffer-size* unless you install a thread-local binding for them with binding, with-bindings etc. There's just a handful of Vars for which thread-local bindings are installed by lower level Clojure machinery, such as *warn-on-reflection* and *read-eval*, making them set!-able at top-level; user-defined Vars are not set!-able at top-level. The root binding of a Var can be changed with e.g. alter-var-root, intern, def, .bindRoot ..., but this should be used sparingly.

As for the rebindable Vars vs. explicit parameters part of the question: going with explicit parameters is almost always ok and usually preferable, just because of the increased maintainability of functions which clearly display all pieces of data they depend on. That being said, if some piece of configuration is likely to be set once, then used by virtually every function call within the app / library ever after, it might make for saner code to define an earmuffed Var, document it well and put the config in it (and this might be one of the rare cases where changing a Var's root binding outside of the form which defines might be ok).

To summarise, use your best judgement, if unsure -- err on the side of explicit parameter passing.

Upvotes: 3

Related Questions