What would be good/idiomatic way of naming functions that either fail or return nothing?

Example:- I am using a library [called failjure. For some reason I am not allowed to link that library here] for representing failed computations. So coming up with functions that return nothing of significance or return a failure is a common scenario.

(defn transition-possible? [id]
  (let [state1 (foo id)
        state2 (bar id)]
    (if (= state1 state2)
      (f/fail "The states cannot be equal"))))

The return value of transition-possible? does not matter here. You are only interested if it returns a failure. But naming it transition-possible? give an impression that the function would return a true or false which is the case here.

How should I go about naming the function here?

First of all: I think you should use when rather than if since you’re not doing any branching.

Secondly, I’m guessing (f/fail "The states cannot be equal") returns a truthy value? Then you should probably call your predicate transition-blocked?, transition-impossible? or cannot-transition? instead.

Would adding a spec to your problem solve your need?

Failjure is based on monadic error handling, which comes from Haskell. In Haskell, type signatures are used for this. And when reading Haskell code, I allways get this information from the type signatures. Elm is another example.

Edit: here’s a way to do it, there might be better ways. I also realized that I might want to prefix failing functions with try-, so that’s what you were really asking for!

(ns scratch.fail
  (:require [failjure.core :as f]
            [clojure.spec.alpha :as s]
            [failjure.spec]))

(defn try-parse-int [s]
  (f/try* (Integer/parseInt s)))

(s/fdef try-parse-int
  :args (s/cat :s string?)
  :ret (s/or :fail :failjure.spec/failure
             :success int?))
2 Likes

I like the idea of a naming convention. I have seen use of monadic failure techniques with clojure fail because of confusion over which functions are monadic and which are not.

Scott Wlaschin’s amazing series of posts and talks on the subject use a railway analogy. In a blog post extending the same idea to Clojure they use the naming convention of adding equals signs to the beginning and end of the function to show it is monadic [or monoidal? One of the two :slight_smile: ]

In your example the function could be called:

(defn =transition-possible= [id] ...)

That said I am slightly bothered by the example you gave as it has no return value. Normally such a function would either return a success case or a failure case so the functions can be chained without further manipulation.

Just realised that you were explicitly asking about functions that fail or return nothing! Using the railway analogy again how about naming it:

(defn =transition-possible=| [id] ... )

The extra bar character ("|") would denote that this is an “end of the line” function. This is similar to Scott’s analogy of converting a “dead end function” - called UpdateDb in his example to a two track function that can be chained/composed. The image is taken from slide of 115 from the talk linked in Scott’s ROP page.

railway-oriented-programming-115-638

There may be better choices of characters out there to use e.g. “¬” ?? :slight_smile:

1 Like

What would the equals signs mean then? "Two tracks in, two tracks out?

For my try-parse-integer above, would you prefer -parse-integer=? But that might make it a private function.

What would the equals signs mean then? "Two tracks in, two tracks out?

Yes two tracks in and two tracks out, success and fail, these are the only really chainable ones, but the other types are worth identifying so they can be converted consistently I guess.

Oooh - plus equals might be a good one for this: “±” . Not sure if Clojure supports such Unicode characters though … Plus–minus sign - Wikipedia :slight_smile:

(defn =transition-possible± [id] ... )

Hmmmm …

Makes sense. I think I would use this :slight_smile:

Personally have a rule(not mature yet) on this:

You said a function either fail or return nothing, I think that is pretty common in Clojure(when you write web service) or in ClojureScript. e.g.

  • query cache may return nothing or fail(connection error)
  • update database may fail(many causes)
  • parsing request may fail
  • http may fail
  • JSON parsing may return nothing

There’re so many cases. And the point is, sometimes we care about the type of failure, sometimes we don’t and sometimes we even don’t care about where it happen.

Instead of naming functions that either fail or returning nothing, I prefer to naming function that will never fail. There’re only few kinds of functions that will never fail.

  1. predicate, when you use (x? foo), this won’t fail, must be either logical true or logical false.
  2. definition, when you use (def-x foo ...), can only be fail for syntax
  3. data-transform, when you use (->x ...) or (x->y ...) , this won’t fail, unless pass in the wrong shape.
  4. maybe there’re more cases I’m still thinking.

The result is when I wrote function for these kind of jobs, I won’t allow it fail, and this is easy to achieve and easy to test.

It’s called a “guard”

=> you could name your function guard-transition.

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.