clojure

weavejester 2025-08-05T15:00:45.807019Z

Is there a way to turn off or ignore *warn-on-reflection*` for a particular code segment? My use-case is that if I don't know the type of a value, using reflection is probably more efficient than writing a cond to check the type, but I also don't want the reflection warning popping up all the time.

borkdude 2025-08-05T15:02:13.707789Z

I do it like this:

(set! *warn-on-reflection* false)

;; code

(set! *warn-on-reflection* true)

borkdude 2025-08-05T15:03:04.174849Z

(or if you don't want true, capture the old value first and then restore that one)

weavejester 2025-08-05T15:03:07.576179Z

If it's a library though... I guess I'd need to do something like:

(def warn-on-reflection *warn-on-reflection*)
(def *warn-on-reflection* false)
...
(def *warn-on-reflection* warn-on-reflection)

weavejester 2025-08-05T15:04:07.333079Z

I daresay I can't use a binding for this because it needs to be a top-level form, as that's the unit of compilation.

borkdude 2025-08-05T15:04:08.073179Z

if it's a library it's still fine to put it to true, it won't affect other namespaces

borkdude 2025-08-05T15:04:17.334219Z

that's correct

weavejester 2025-08-05T15:04:30.991359Z

Wait, it won't affect other namespaces? Why?

borkdude 2025-08-05T15:04:52.362889Z

because every time a namespace is compiled, it's re-bound to the original value

borkdude 2025-08-05T15:05:30.937209Z

similar to *ns*

weavejester 2025-08-05T15:06:39.470389Z

Ohh.. Huh. I didn't know that. I guess Leiningen must inject it into namespaces when they're loaded, or use some sort of command line switch.

borkdude 2025-08-05T15:07:05.144069Z

you can affect the root binding , e.g. using alter-var-root in user.clj

borkdude 2025-08-05T15:07:13.377279Z

but as long as you don't do that, you're fine

weavejester 2025-08-05T15:07:55.857829Z

Ah, and then the compiler will use that as the default.

borkdude 2025-08-05T15:07:59.243149Z

right

weavejester 2025-08-05T15:08:20.115279Z

Thanks for all the help - it's very much appreciated.

🙏 1
2025-08-05T16:28:00.692119Z

I'm not sure reflection is faster than cond over instance of checks

weavejester 2025-08-05T16:29:03.599379Z

I think you might be right; I've just run a few checks to confirm, and instance checking seems to be faster, which I'm surprised by.

2025-08-05T16:30:32.252139Z

I think reflection is more open ended. But a conditional on instance of is more local and closed so it can probably be optimized more easily.

2025-08-05T16:46:01.896279Z

class checking and downcasting is extremely fast because you're basically doing an enum check, whereas reflection requires you lookup a substantial data structure that isn't usually gonna be in cache and iterate over it before eventually finding the right method, doing some validation, and then jumping to the body.

1
weavejester 2025-08-05T16:49:39.869339Z

My assumption was that there'd be some optimisation around partial reflection. i.e. if the compiler knows there's only three possible results given the types it knows, it can optimise the lookup. I guess that's not a common scenario in Java, though.

👍 1
exitsandman 2025-08-05T17:13:03.630689Z

as far as I understand clojure reflective calls are close to a naive implementation, largely amounting to calling getMethods on the target class and iterating through the methods until a valid one is found (with plenty of class hierarchy checks and array allocations along the way).

Reut Sharabani 2025-08-06T09:03:21.353559Z

I'm curious: Why turn it off it in a library? Why not convey to the user that reflection is happening?

borkdude 2025-08-06T09:04:55.809799Z

isn't the purpose of a warning that you perhaps missed something and want to take action on it? in this case you are completely aware of reflection and don't want to be warned about it?

borkdude 2025-08-06T09:05:36.607619Z

you could also insert the call to clojure.lang.Reflector yourself btw, to bypass the warning

Reut Sharabani 2025-08-06T09:05:38.466789Z

I'm usually not aware of everything happening in libraries, and if I want to turn it off for some library call I can do it myself. I'd be surprised to find a code that turns off what I consider a user setting in a library

borkdude 2025-08-06T09:06:36.084359Z

> and if I want to turn it off for some library call I can do it myself. warn on reflection doesn't happen during calls, it happens during compilation

Reut Sharabani 2025-08-06T09:07:30.964149Z

so wrapping the call with (def *warn-on-reflection* false) ... won't work?

borkdude 2025-08-06T09:11:26.141659Z

no it is a compilation thing, not a runtime thing

Reut Sharabani 2025-08-06T09:11:27.639229Z

anyway intuitively I'd still want to be able to control it somehow

Reut Sharabani 2025-08-06T09:13:41.023459Z

something like

(def warn-on-reflection *warn-on-reflection*)
(def *warn-on-reflection* (or *library-config-var*
                              *warn-on-reflection*))
...
(def *warn-on-reflection* warn-on-reflection)

Reut Sharabani 2025-08-06T09:14:55.320899Z

well, it won't work with booleans, but you get the point 🙂

borkdude 2025-08-06T09:15:42.521449Z

A library author can still just write something like this:

(clojure.lang.Reflector/invokeInstanceMethod "hello" "length" (into-array []))
and you won't get a warning.

borkdude 2025-08-06T09:16:28.367339Z

And even if you detected that reflection was happening in a library what were you going to do about it as a user? send a PR?

Reut Sharabani 2025-08-06T09:21:32.787119Z

For me the point is that I'd know about it. And maybe the compiler can optimize them some day, but it won't optimize java reflection calls, so I guess they're not going away

Reut Sharabani 2025-08-06T09:22:11.075929Z

anyway it's straying off topic, I was curious about this behavior

borkdude 2025-08-06T09:22:51.134889Z

There's a more accurate way to detect reflection, even from clojure.lang.Reflector etc, which is using a java agent, see e.g. https://www.graalvm.org/jdk21/reference-manual/native-image/dynamic-features/Reflection/

👀 1
borkdude 2025-08-06T09:23:24.809909Z

that's how I found this one: https://github.com/clojure/clojure/commit/69387c5e7d617ebe17ebaaa97344a1bb6a5f0817

👀 1
gaverhae 2025-08-06T13:37:00.189889Z

> i.e. if the compiler knows there's only three possible results given the types it knows Reflection is enumerating methods at runtime; given the JVM execution model there isn't really a way for the compiler to know the set of methods that will be available at runtime, as the classpath may be different (as well as the base JVM version).

2025-08-06T13:52:39.509279Z

I understand the intuition of not wanting libraries to turn off the warning. I've had scenarios where you bang your head on why some piece of code is so slow, only to start looking into a library and realizing it's using reflection and that's why.

2025-08-06T13:53:22.146689Z

Though often it was closure core itself 😂, and since that's AOT compiled you don't get warned.