Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Environment dependent dispatch of protocols/multimethods in clojure

I'm facing a problem in how to architecture a particular piece of my software. Lets say, I have a function called make-temp-dir (and many others) that does some dark magic depending on the current OS. I want to be able to put the implementations of these methods for each OS in a separate namespace.

Firstly, I believe protocols (if possible) or multimethods are the solution to this. However, I've never seen an example of using these with implementations spanning over multiple namespaces. And I'm not able to figure how this'd work out.

Second, if I use protocols for this, I'll have to call the methods something like

(make-temp-dir current-os arg-1 arg-2)

Somehow, passing the os as the first argument all the time doesn't look too good to me. For semantic sake, I'd wish the make-temp-dir take intelligent decisions depending on the OS. Sure I can use some macros and do something like

(doto current-os
  (make-temp-dir arg-1 arg2))

but that feels wrong.

How should this be done? Or am I going the wrong way? Any help appreciated.

Edit: Okay, thanks a ton to @kotarak, I managed to get something working. For anyone that stumbles on this, https://gist.github.com/2477120. Its working fine, I think I'll go with that. Thanks everyone.

like image 411
sharat87 Avatar asked Apr 23 '12 15:04

sharat87


2 Answers

(ns your.utils)

(def current-os)

(defmulti make-temp-dir
  (fn [& _] current-os))

(ns your.utils.mac)

(defmethod make-temp-dir :mac-os-x
  [a b]
  (...))

(ns your.utils.win)

(defmethod make-temp-dir :windows
  [a b]
  (...))

In your startup code you have to initialize current-os with alter-var-root before using any of the utility functions.

(let [os (find-os)]
  (alter-var-root #'current-os (constantly os))
  (require (case os
             :mac-os-x 'your.utils.mac
             :windows  'your.utils.win)))

Hope that gets you started.

like image 150
kotarak Avatar answered Sep 18 '22 23:09

kotarak


I can't say for certain, but it sounds like you may end up reinventing a wheel that Java provides you with. Try out https://github.com/Raynes/fs for a convenient wrapper on some of what Java provides beyond the basic tools in clojure.java.io ( http://clojuredocs.org/clojure_core/clojure.java.io ).

You may find also https://github.com/drakerlabs/milieu useful if your question extend beyond OS-specific branching to environment-specific configuration values. I wrote this code as part of our proprietary projects here at Draker, and we've just recently released it as free software. We haven't yet officially announced it to the community, but it is in Clojars and ready for use. Feedback is appreciated! The concept that drove its creation was environments in the sense of dev/test/staging/production etc, but I see no reason why it couldn't be used to configure variables for different OS environments as well.

like image 38
rplevy Avatar answered Sep 20 '22 23:09

rplevy