:PROPERTIES: :ID: b413e4db-1367-4936-8a46-cd5b86178e29 :END: #+title: Either in Clojure #+author: Yann Esposito #+date: [2022-08-15] - tags :: [[id:a5be1daf-1010-428f-a30f-8faf95c1a42f][blog]] - source :: * Either Either or Exceptions? When you start working with Clojure (or many other programming language) a classic notion of error is, for your function, to return nothing is an error occurred. But quite often you want to convey more detail about the error so you could act differently depending on it. Or provide a more detailed error message to your end user, etc… The recommended method to handle errors in Clojure (and a lot of other programming languages) is to throw exceptions. While this is perfectly pragmatic and reasonable, exceptions have a few undesirable properties. First, they are impure, which somehow break the principles behind functional programming. So if you are using Clojure chance are you prefer to keep it as pure as possible. Second, exceptions are generally expensive, and should probably be avoided if possible. (*TODO*: write a short benchmark). Third, Exceptions lack of composability properties and are often hidden. It is generally impossible to know if a function could or could not throw an exception. And also if you should or should not do something about it. Also, while possible it is not very natural to accumulate errors generated by a sequence of actions. The same could be said if you want to transform the error depending on the code context. Here are two example of code: #+begin_src clojure ;; Example of accumulating values and errors (for [x things] (try (do-some-action %) (catch Exception e (do-something-with-exception e)))) ;; Example of tranforming value (try (do-some-action x) (catch Exception e (transform e))) #+end_src We see this is easy, but, I don't know, it looks a bit cumbersome to me. So what is the other possibility? In the Statically Typed Pure Function Programming world people often use ~Either~. What is this? Mainly this is a type that represent the notion of: "We have either something or an error." Either contains two component, by convention a left and a right. And also by convention the right contain the value while the left contain the error. Why? Because right also means correct in English. So ~Either~ is a sum type. Sum types is probably THE feature I miss the most in many programming languages. Anyway, it is not difficult to simulate a sum type. Here are a few possible representations: Using a tag field that indicate if the content is a right or a left: #+begin_src clojure {:type (enum :left :right) :content value-or-error} ;; example for (Right 42) {:type :right :content 42} ;; exaple for (Left "error") {:type :left :content "error"} #+end_src Another way to prevent some potential issue with conflicting different schemas (imagine if you had to save the previous representation within Elasticsearch for example, the mapping would probably be difficult to write). #+begin_src clojure {:type (enum :left :right) (optional-key :left) Error (optional-key :right) Value} ;; example for (Right 42) {:type :right :right 42} ;; exaple for (Left "error") {:type :left :left "error"} #+end_src And the last one not as generic, but good enough for our use case, both terser, easier to read and manipulate: #+begin_src clojure {(optional-key val): Value (optional-key err): Error} ;; example for (Right 42) {:val 42} ;; example for (Left "error") {:err "error"} #+end_src So we'll choose this one.