Welcome! Please see the About page for a little more info on how this works.

+5 votes
in Clojure by

When using some-fn with 3 predicates the followed evaluation order is different and some-fn short-circuits differently:

with 2 predicates:

((some-fn #{42} #{1}) 1 42)
=> 42

with 3 predicates:

((some-fn #{42} #{1} :third-pred) 1 42)
=> 1

with 4 or more predicates:

((some-fn #{42} #{1} :third-pred :fourth+more-pred) 1 42)
=> 42

The docstring for some-fn says: ".... Note that f [the function returned by some-fn] is short-circuiting in that it will stop execution on the first argument that triggers a logical true result against the original predicates."
I read this as only the current 3-arity behavior complying with that.

Possible solution:
I think this needs a docstring fix replacing "the first argument" with "an argument". A patch to make the short-circuiting consistent might be a breaking change, due to returning possibly a different logical true value.

Also, this docstring line is the same as at "every-pred", which has the same different evaluation order and short-circuiting behavior with its 3 predicate arity versus its 2 and 4&more-arity. The impact of this with "every-pred" is less because every-pred only returns a boolean true or false, while "some-fn" returns a logical true value.

1 Answer

0 votes

At 4 or more predicates the strategy changes. Instead of testing in the order of (p1 x), (p2 x), (p1 y), (p2 y) etc., it switches to (p1 x), (p1 y), (p2 x), (p2 y) ...

This inconsistency feels like a bug to me.

The 3-predicate version checks each predicate against arg1 then each against arg2 then each against arg3 etc. The 2- and 4+predicate versions check pred1 against each arg, then pred2 against each arg, then pred3 against each arg, etc. The docstring can be read either way (in my opinion) but for the non-3-predicate version, it actually stops at the first _predicate_ that is truthy on any of the arguments. So I think the 3-predicate version is "wrong" and the docstring is a bit misleading.