Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/rufoa/try-let
Better exception handling for Clojure let expressions
https://github.com/rufoa/try-let
clojure exception-handling
Last synced: 4 months ago
JSON representation
Better exception handling for Clojure let expressions
- Host: GitHub
- URL: https://github.com/rufoa/try-let
- Owner: rufoa
- Created: 2015-10-26T03:03:02.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2019-02-01T01:39:23.000Z (about 6 years ago)
- Last Synced: 2024-04-23T22:19:28.080Z (10 months ago)
- Topics: clojure, exception-handling
- Language: Clojure
- Homepage:
- Size: 15.6 KB
- Stars: 18
- Watchers: 5
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
try-let
=======`try-let` is a Clojure macro designed to make handling some exceptions slightly nicer. It acts like `let`, but allows you to catch exceptions which may be thrown inside the binding vector. Exceptions thrown inside the body of the `try-let` are deliberately ignored.
[![Build Status](https://travis-ci.org/rufoa/try-let.png?branch=master)](https://travis-ci.org/rufoa/try-let)
## Installation ##
`try-let` is in Clojars. To use it in a Leiningen project, add it to your project.clj dependencies:
[![Clojars Project](https://clojars.org/try-let/latest-version.svg)](https://clojars.org/try-let)
then require `try-let` in your code:
```clojure
(ns my.example
(:require [try-let :refer [try-let]]))
```## Motivation ##
It can be quite difficult to combine `try/catch` with `let` properly. Clojure pushes you towards one of two patterns, neither of which is ideal.
```clojure
(try
(let [value (func-that-throws)]
(act-on-value value))
(catch Exception e
(log/error e "func-that-throws failed")))
```In the above pattern, the scope of the `try/catch` is too great. In addition to `func-that-throws`, it also affects `act-on-value`.
```clojure
(let [value
(try (func-that-throws)
(catch Exception e (log/error e "func-that-throws failed")))]
(act-on-value value))
```In the above pattern, the scope of the `try/catch` is correct, affecting only `func-that-throws`, but when an exception is caught, `act-on-value` is evaluated regardless and must handle the exceptional case when `value` is nil.
## Use ##
With `try-let`, we can instead do:
```clojure
(try-let [value (func-that-throws)]
(act-on-value value)
(catch Exception e
(log/error e "func-that-throws failed")))
```This allows the scope of the `try/catch` to be made as precise as possible, affecting only `func-that-throws`, and for evaluation to only proceed to `act-on-value` when `value` is obtained without error. In this way, `try-let` can be thought of as similar to `if-let`, where the body is only evaluated when the value of the binding vector is not nil.
You can have multiple `catch` stanzas for different exceptions. Much of what you'd expect to work in a normal `let` works:
```clojure
(try-let [val-1 (risky-func-1)
val-2 (risky-func-2 val-1)]
(log/info "using values" val-1 "and" val-2)
(* val-1 val-2)
(catch SpecificException _
(log/info "using our fallback value instead")
123)
(catch RuntimeException e
(log/error e "Some other error occurred")
(throw e))
(finally
(release-some-resource)))
```As an alternative, you can also put `catch` stanzas before other body expressions:
```clojure
(try-let [val-1 (risky-func-1)]
(catch Exception e
(log/error e "Problem calling risky-func-1")
0)
(try-let [val-2 (risky-func-2 val-1)]
(catch Exception e
(log/error e "Problem calling risky-func-2")
0)
(log/info "using values" val-1 "and" val-2)
(* val-1 val-2)))
```This makes the code logic more linear, where exceptions are handled closer to where they appear.
## Slingshot support ##
There is also a `try+-let` macro which is compatible with [slingshot](https://github.com/scgilardi/slingshot)-style `catch` stanzas.
## License ##
Copyright © 2015-2019 [rufoa](https://github.com/rufoa)
Distributed under the Eclipse Public License, the same as Clojure.