Ertuğrul Çetin
Ertuğrul Çetin

Reputation: 5231

How to wrap Exception in Clojure Macro?

I would like to wrap exception which has been thrown by system or user(does not matter) and force it to return some value.

I wrote macro for it but it does not work.

Macro:

(defmacro safe-fn
  [form]
  (try
    `(do ~form)
    (catch Throwable e
      1)))

Usage: (safe-fn (throw (RuntimeException. "Try me!")))

Actual output: RuntimeException Try me! clojure-brave-and-true.core/eval2219 (form-init6122238559239237921.clj:1)

Desired output: 1

Upvotes: 4

Views: 435

Answers (2)

Alan Thompson
Alan Thompson

Reputation: 29958

The macro with-exception-default from the Tupelo library does exactly what you want:

Default Value in Case of Exception

Sometimes you know an operation may result in an Exception, and you would like to have the Exception converted into a default value. That is when you need:

(with-exception-default default-val & body)
  Evaluates body & returns its result.  In the event of an exception the
  specified default value is returned instead of the exception."

(with-exception-default 0
  (Long/parseLong "12xy3"))
;=> 0

This feature is put to good use in tupelo.parse, where you will find functions that work like this:

(parse-long "123")                  ; throws if parse error
;=> 123
(parse-long "1xy23" :default 666)   ; returns default val if parse error
;=> 666

Upvotes: 2

Sam Estep
Sam Estep

Reputation: 13324

Macros are just functions that return code to be evaluated, so you could write safe-fn like this:

(defmacro safe-fn
  [form]
  `(try
     ~form
     (catch Throwable ~'_
       1)))

Example:

(safe-fn (throw (RuntimeException. "Try me!")))
;=> 1

See my answer to this question for more detail on macros, and specifically on using them to catch exceptions.

Upvotes: 7

Related Questions