clojurecontracts

More readable messages with :pre and :post?


In clojure I am using :pre like this

user=> (defn cannot-take-empty [x] {:pre [((complement empty?) x)]} 1)
#'user/cannot-take-empty
user=> (cannot-take-empty #{})
AssertionError Assert failed: ((complement empty?) x)  user/cannot-take-empty (NO_SOURCE_FILE:186)

That's great, but it doesn't explain the business reason why it doesn't make sense to pass in an empty collection. (Or a collection with more than five elements, or a collection that has two keys present but not another, or whatever the rule of the day is.) This is potentially even more confusing for the user if the precondition uses a private function.

Is there a way to provide more useful feedback to the user like an error message, when using :pre and :post?


Solution

  • Apparently pre and post conditions are designed for usecases where reporting the clauses provides enough information to the developer, i.e. it is self-explanatory. If you wish to provide more explanation, it is idiomatic to use assert.

    But you can abuse the fact that the whole condition is always reported e.g. like this:

    {:pre [(do "It can't be empty because of..."
               (seq x))]}
    

    And it will report something like

    AssertionError Assert failed: (do "It can't be empty because of..." (seq x)) ...