Repository navigation
Conversation
Integrant calls reflike? on every value in a configuration, several times per init. On the JVM, satisfies? is slow for values that do not implement the protocol, which can be nearly all of them, so init time can grow noticeably with the size of the configuration. Check for the protocol interface instead, which the Ref and RefSet records implement.
|
an alternative approach could be to change |
|
On the one hand this could break any existing application that uses a custom reflike that's created via The It also seems unlikely to me that anyone would implement their own So I think I'm in favour of this change, after giving it a little thought. However, I'll leave this PR open for a little while to give folk time to object. |
reflike?is called on every value in a configuration, several times perinit(dependency graph, refvalidation, ref resolution). On the JVM,
satisfies?is slow when the answer is false, as it searches the classhierarchy of the value for a protocol implementation and does not cache misses. Most values in a large configuration
are not refs, so
inittime can get long.This changes
reflike?to check for the protocol's interface withinstance?on the JVM.RefandRefSetimplement
RefLikeinline, so they are still recognized. ClojureScript keepssatisfies?, which is fast there.Babashka also supports the interface check.
There is one behaviour difference: a type that implements
RefLikethroughextend-protocolorextend-typewould no longer be treated as a ref on the JVM. I don't know if anyone would be doing that.In our main app Integrant goes through 400k+ nodes, so this has a meaningful impact on our app's startup time.
Benchmark
A configuration of 100 components whose values are plain nested data (~117k nodes in total), each with a ref to the
previous component:
Median of 10 runs of
ig/init+ig/halt!(Clojure 1.11.4, JDK 25, M4):