Custom Errors in Clojure

Our first example demonstrates how to create custom errors in Clojure. While Clojure doesn’t have a built-in error type like Go, we can create our own error type using a record.

(ns custom-errors.core
  (:require [clojure.string :as str]))

;; A custom error type usually has the suffix "Error".
(defrecord ArgError [arg message]
  ;; Adding this toString method makes ArgError behave like an error.
  Object
  (toString [this]
    (str (:arg this) " - " (:message this))))

(defn f [arg]
  (if (= arg 42)
    ;; Return our custom error.
    [nil (->ArgError arg "can't work with it")]
    [(+ arg 3) nil]))

(defn -main []
  ;; In Clojure, we don't have a direct equivalent to errors.As,
  ;; but we can check the type of the error manually.
  (let [[result err] (f 42)]
    (if (instance? ArgError err)
      (do
        (println (:arg err))
        (println (:message err)))
      (println "err doesn't match ArgError"))))

To run the program:

$ lein run
42
can't work with it

In this Clojure version:

  1. We define a custom ArgError record that takes an arg and a message.

  2. We implement a toString method for ArgError to make it behave like an error.

  3. The f function returns a vector with two elements: the result (or nil) and the error (or nil).

  4. In the -main function, we use instance? to check if the error is of type ArgError.

  5. If it is, we print the arg and message fields of the error.

This approach provides a way to create and handle custom errors in Clojure, similar to the custom error types in other languages. While Clojure doesn’t have a built-in error type or errors.As function, we can achieve similar functionality using records and type checking.