4

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

Ertuğrul Çetin
  • 5,131
  • 5
  • 37
  • 76

2 Answers2

7

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.

Community
  • 1
  • 1
Sam Estep
  • 12,974
  • 2
  • 37
  • 75
2

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
Alan Thompson
  • 29,276
  • 6
  • 41
  • 48