Last week, there was a mailing list post on the clojure-dev mailing list noting that several of the new predicates in Clojure 1.9 alphas return true or nil. The three new predicates are: qualified-keyword?, qualified-ident?, and qualified-symbol?. Previously, all predicate functions in Clojure core, i.e. functions that end in a ? have returned true/false. In this post I want to examine the pros and cons of this new behaviour.

If I’ve missed anything here, please get in contact and I’ll update the post.

Pros to some predicates returning nil

The main argument for some predicates returning nil is that the predicate still returns a falsy value. Idiomatic Clojure code usually doesn’t need to distinguish between nil and false.

The docstrings for qualified-keyword? for example says: “Return true if x is a keyword with a namespace”. It doesn’t say anything about what happens if it doesn’t have a namespace, so returning nil or false are both technically valid interpretations.

Not coercing the output from qualified-keyword? into a boolean is faster. On my computer qualified-keyword? takes roughly 3.5 ns to run, and a version that returns a boolean value takes around 6.5 ns. In absolute terms they are both pretty small though.

The first two points aren’t strong arguments for returning nil, rather they argue that it doesn’t matter whether the functions return nil or false.

Cons to some predicates returning nil:

The biggest downside to this change is that it breaks a core convention that Clojure and the community has held around predicates, namely that any function ending in ? returns true or false. This is my biggest concern about the changes. You can find this expectation in:

Programming Clojure: “A predicate is a function that returns either true or false. In Clojure, it is idiomatic to name predicates with a trailing question mark, for example true?, false?, nil?, and zero?.” - Programming Clojure, 2nd Ed., Page 27.

Clojure’s own library coding standards: “Use ‘?’ suffix for predicates. N.B. - predicates return booleans”. That page also has the disclaimer: “Rules are made to be broken. Know the standards, but do not treat them as absolutes.”

The community Clojure Style Guide: “The names of predicate methods (methods that return a boolean value) should end in a question mark (e.g., even?).”

All of the Clojure standard library functions that end in a ? return a boolean value. Anyone learning Clojure would be justified in assuming that all functions that end in ? return a boolean value if that’s the convention they have always seen.

A mailing list thread about this exact question, whether all Clojure functions that end in ? should return a boolean value.

Tutorials Point: “Predicates are functions that evaluate a condition and provide a value of either true or false.”

StackOverflow on naming rules: “The main function naming conventions seem to be … Use ? to indicate a predicate that returns true or false: sequential?”

The second biggest problem is that qualified-keyword? can return three values. “How is that?” you might be asking, “Didn’t you just say that the functions return true or nil?”. I thought so too. However as I was looking at the implementation of these functions, I realised that qualified-keyword? can return false as well, if not given a keyword. For example:

It is fairly common to use group-by or juxt with a predicate function to partition a collection into two groups. If you use any of the new qualified* functions, you will end up with three groups. Based on Alex Miller’s tweet, it seems like this was considered and accepted.

If these predicates are used at the boundaries of systems or in interop with Java, then it would be easy to forget that the qualified* predicates may return nil, and end up passing null into a Java method as a parameter when you meant to pass false. You could also return false under certain input when you expected the function to only return true or nil, or return nil when you were expecting the result to be a boolean. These kinds of bugs can be very subtle, especially with Clojure’s falsy handling.

Clojure gets similar benefits from the JVM when it can mark the function as returning a Boolean.

Historically, Clojure has made a distinction between functions that return truthy and those that return true. There are predicate functions in core that return a truthy value like some and every-pred, but they don’t end in a ?. This change starts to dissolve that distinction.

Summary

Personally, I don’t see a strong reason to keep the current behaviour of the new qualified predicate functions, but you might see things differently. Whatever the outcome, I’m glad that in Clojure we don’t have to name all of our boolean functions with an “Eh” suffix.