liveBook · Manning

Reflection

As explained in Clojure: The Essential Reference

Java reflection is an API mechanism for discovering class structure and invoking constructors or other members at runtime.

Reflection lets a program inspect Java types and find members at runtime. In Clojure, it has two practical faces: `clojure.reflect/reflect` exposes a type’s structure for inspection, while the compiler may use reflective calls when it cannot determine the type needed to resolve a Java method or array operation. That flexibility can cost speed. section 21.6 section 2.1.1

To inspect a type with `clojure.reflect/reflect`:

  • Pass an object or a class. The result has `:bases` for direct superclasses and interfaces, `:flags` for modifiers, and `:members` for public members; inspection includes constructors, methods, signatures, and return types. section 21.6
  • Pass `:ancestors true` to include superclasses and interfaces at every level. Pass `:reflector` to substitute another reflector; the default uses Java reflection and loads the class for inspection. section 21.6
  • Use `type-reflect` when the input is a class. It provides the same functionality, whereas `reflect` also accepts objects. section 21.6

Inspect a map

After `(require '[clojure.reflect :as r])`, `(keys (r/reflect {}))` yields the keys `:bases`, `:flags`, and `:members`. Enabling `:ancestors true` expands the inspection beyond the map’s direct bases. section 21.6

Inspection is different from avoiding reflective calls in compiled code. With `(set! *warn-on-reflection* true)`, the compiler reports calls whose target types it cannot resolve. In a request-signing example, warnings for `.getBytes` and `.doFinal` disappear when their parameters are hinted `^String` and `^Mac`. A sample run of 100,000 requests fell from about 1,054 ms to 449 ms after those changes; measure performance in the application at hand. section 2.1.1

The same issue arises with primitive arrays: dereferencing a Var can leave the compiler knowing only that it has an object. For an integer array, `aset` then produces a reflection warning. Hint the array as `^ints` or use `aset-int`; both remove the warning in the shown example. Reflection remains useful for discovery, but known types are worth making explicit on performance-sensitive calls. section 21.7.6

How Clojure: The Essential Reference covers it

How deep it goes
Defines inspection inputs, result keys, and options, then works through type hints and typed array setters without detailing Java reflection internals.
Examples
Uses map inspection, request signing with a timed run, and integer-array updates that trigger or avoid warnings.
What it assumes
Assumes Clojure function and Java-call syntax while defining `reflect` inputs and output keys and demonstrating type hints.
What you can do after
Diagnose/debug with reflection warnings, inspect Java types via `clojure.reflect/reflect`, and remove demonstrated reflective calls with type hints or `aset-int`.
How it connects
Connects reflection to Java interoperability, type hints, compiler warnings, Var indirection, and primitive arrays.

Also explained in

Compare how 13 books explain reflection →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Clojure: The Essential Reference. The section links point to the parts of the book it draws on.