Learn how reflection shows up in Clojure, when it matters, how to surface it with warnings, and how to eliminate it in hot interop-heavy paths without over-annotating the whole codebase.
Reflection: Runtime discovery of methods, fields, or constructors because the compiler did not know enough about the target type ahead of time.
Reflection happens when the runtime has to discover method or field behavior dynamically because the compiler did not know enough about the target type ahead of time. In Clojure, that usually matters around Java interop, not around ordinary map-heavy business logic.
Typical triggers:
That means reflection warnings are especially worth reviewing in:
That is why reflection problems often cluster in the same places where low-level performance work already matters.
1(set! *warn-on-reflection* true)
That does not mean every warning is urgent. It means the warnings tell you where the compiler had to guess at runtime rather than compile a direct path.
Use type hints when they clarify a proven hot interop path:
1(set! *warn-on-reflection* true)
2
3(defn ascii-sum
4 ^long [^String s]
5 (loop [i 0
6 total (long 0)]
7 (if (< i (.length s))
8 (recur (unchecked-inc-int i)
9 (unchecked-add total (long (.charAt s i))))
10 total)))
Here the ^String hint makes the method targets clear enough to avoid reflective dispatch.
The important principle is to hint the thing the compiler is uncertain about:
Randomly sprinkling hints on unrelated values is much less useful.
Some warnings are worth fixing immediately. Some are irrelevant because the path runs rarely. The right process is:
That is better than spraying hints across the codebase just to silence all warnings.
In other words, warnings help you rank work. They do not automatically define what matters most.
Method calls are the most visible case, but reflection also appears around:
That is why interop helpers often benefit from a small amount of explicit typing even when the surrounding code remains completely idiomatic.
That is where the cost compounds.
Not all reflective paths are performance-critical.
Hints should clarify the real runtime target, not simply decorate the code.
Eliminating reflection helps, but it will not rescue a poor workload shape.
Use reflection warnings to find uncertain interop paths, and fix them where profiling shows the cost matters. Hint the actual uncertain boundary rather than decorating the whole codebase. Keep ordinary application code simple, and make hot Java boundaries explicit enough that the compiler can compile a direct path. Reflection is a real runtime tax, but mostly in the places where you are already close to the JVM boundary.