funcool/cats

Add preconditions to -mbind implementations

yurrriq opened this issue · 9 comments

Per #150, et al., mlet can be a little confusing wrt context. In an effort to fail faster (and not wait for #140), we should add preconditions to ensure the proper context in each -mbind implementation.

iirc protocol method implementations can't have :preconditions, but a simple if that throws an error upon encountering a context mismatch should suffice.

Working on it on #173

What do you @yurrriq think about this:

(require '[cats.context :as ctx] :reload)
(require '[cats.core :as m] :reload)
(require '[cats.monad.either :refer [left right]])
(require '[cats.monad.maybe :refer [just nothing]])

(m/mlet [a (just 1) b (right 2)] (m/return (+ a b)))
;; => #<Just 3>

(alter-var-root #'ctx/*strict* (constantly true))
;; => true

(m/mlet [a (just 1) b (right 2)] (m/return (+ a b)))
;; => IllegalArgumentException Context mismatch: you can't mix different context.  cats.context/throw-illegal-argument (context.cljc:33)

It not yet finished (not in master) because I need some fixes before but is a generic approach instead of having assert on each -mbind impl. It just checks if the previously set context is equal to the current provided one and if they mismatches, then the exception is raised if strict mode is enabled.

I think the first example should always fail. The check and error message seem solid, though. What else does strict mode do?

Just that, it disallows overwrite the already set context and checks if the contexts are different and just throws an exception. In any case I agree with you and I will add asserts independently of the strict mode.

(m/mlet [a (just 1) b (right 2)] (m/return (+ a b)))
;; AssertionError Assert failed: Context mismatch: #<Right 2> is not allowed to use with maybe context.

This seems like a much better error message and works as is, without strict mode.

Looks good to me.

Nice, this is already in master ;)