Skip to content

Instantly share code, notes, and snippets.

@AdamClements
Last active December 16, 2015 19:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AdamClements/5488162 to your computer and use it in GitHub Desktop.
Save AdamClements/5488162 to your computer and use it in GitHub Desktop.
A handle macro which gives a more lisp-like way to handle exceptions by wrapping a body in a handler which delegates to different functions depending on the Exception. This allows exception handler re-use as you can put a function name which takes a single exception argument and then use it in multiple places rather than requiring a body as in t…
(defmacro handle [binds & body]
(concat (conj body 'try)
(for [[ex-type ex-fn] (partition 2 binds)
:let [ex-sym (gensym "exception")]]
(if (= ex-type :finally)
(list 'finally (list ex-fn))
(list 'catch ex-type ex-sym (list ex-fn ex-sym))))))
(defmacro handle-fn [binds f]
`(fn [& args#] (handle ~binds (apply ~f args#))))
;;; Simple usage
(handle [Exception (constantly 0)] (do-something-where-error-means-default-to-zero arg1 arg2))
;;; Better example
(handle [InvalidArgumentException log/error
TimeoutException (fn [e] (add-to-retry-queue x))
:finally (fn [e] (.close x))]
(attempt-work x))
;;; Alternatively
(def safely-attempt-work (handle [InvalidArgumentException log/error
TimeoutException (fn [e] (add-to-retry-queue x))
:finally (fn [e] (.close x))]
attempt-work))
(safely-attempt-work x)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment