The implementation for the "class" (the function in question) given
one of fluokitten's protocol is chosen:
1) if it directly implements the protocol => (fn ...) doesn't,
2) if one of its direct super-classes implements the protocol
=> in order fn itself, AFunction and AFn don't,
3) if Clojure can find one implementation by the following algorithm:
a) get all clojure.core/supers of "class" as a set,
b) iterate over the set (i.e. the order is unknown) to keep only
implementors of the protocol),
c) reduces the sequence of implementors left-to-right (the order
is stable now but it is still unknown) and it either prefers
the current / the first result or the second if the latter
is more specific as tested by Class/isAssignableFrom.
The IFn or IFn$... interfaces are in no such relation
so it is always false and the reduction prefers always
the first implementation found,
4) fallback to Object if nothing was found so far.
The important outcome is that it doesn't always work for primitive
functions. It can pick either the specific IFn$... implementation
(which is often the case) or the generic IFn implementation.
The IFn doesn't have to fail it can work and even return the correct
answer but it'll use a suboptimal implementation.
However we can take advantage of #4 above - that is let Object be
the fallback implementation instead of IFn. The primitive version
will always have a priority if it exists.
The implementation for the "class" (the function in question) given one of fluokitten's protocol is chosen: 1) if it directly implements the protocol => (fn ...) doesn't, 2) if one of its direct super-classes implements the protocol => in order fn itself, AFunction and AFn don't, 3) if Clojure can find one implementation by the following algorithm: a) get all clojure.core/supers of "class" as a set, b) iterate over the set (i.e. the order is unknown) to keep only implementors of the protocol), c) reduces the sequence of implementors left-to-right (the order is stable now but it is still unknown) and it either prefers the current / the first result or the second if the latter is more specific as tested by Class/isAssignableFrom. The IFn or IFn$... interfaces are in no such relation so it is always false and the reduction prefers always the first implementation found, 4) fallback to Object if nothing was found so far.
The important outcome is that it doesn't always work for primitive functions. It can pick either the specific IFn$... implementation (which is often the case) or the generic IFn implementation. The IFn doesn't have to fail it can work and even return the correct answer but it'll use a suboptimal implementation.
However we can take advantage of #4 above - that is let Object be the fallback implementation instead of IFn. The primitive version will always have a priority if it exists.
Signed-off-by: Kamil Toman kamil.toman@leafclick.com