We're updating the issue view to help you get more done. 

Make `satisfies?` as fast as a protocol method call

Description

Currently `satisfies?` doesn't use the same impl cache used by protocol methods, making it too slow for real world usage.

With:

1 2 3 4 (defprotocol p (f [_])) (deftype x []) (deftype y []) (extend-type x p (f [_]))

Before patch:

1 2 3 (let [s "abc"] (bench (instance? CharSequence s))) ;; Execution time mean : 1.358360 ns (let [x (x.)] (bench (satisfies? p x))) ;; Execution time mean : 112.649568 ns (let [y (y.)] (bench (satisfies? p y))) ;; Execution time mean : 2.605426 µs

Cause: `satisfies?` calls `find-protocol-impl` to see whether an object implements a protocol, which checks for whether x is an instance of the protocol interface or whether x's class is one of the protocol implementations (or if its in an inheritance chain that would make this true). This check is fairly expensive and not cached.

Proposed: Extend the protocol's method impl cache to also handle (and cache) instance checks (including negative results).

After patch:

1 2 (let [x (x.)] (bench (satisfies? p x))) ;; Execution time mean : 79.321426 ns (let [y (y.)] (bench (satisfies? p y))) ;; Execution time mean : 77.410858 ns

Patch: CLJ-1814-v7.patch (depends on )

Environment

None

Status

Assignee

Unassigned

Reporter

Nicola Mometto

Approval

Vetted

Patch

Code and Test

Priority

Critical