clojure-dev 2026-09-14

Are the JVM bytecode semantics high level enough that Clojure doesn't need to implement any duplicated behavior from a Java compiler in order to do all the work it wants, including interop, class generation, etc? This has been my impression, but I'd like to get a more informed opinion before I make baseless claims. My intention is to compare something like Java -> JVM bytecode to C++ -> LLVM IR. Since LLVM IR is significantly lower level than C++'s semantics, a C++ compiler is required to get from C++ to LLVM IR. My impression is that a Java compiler is not required to access Clojure's level of Java semantics from JVM bytecode. Or maybe this is more apples and oranges than I'm thinking.

hard to understand what you are getting it from the jvm perspective, there is nothing a java compiler can produce that is outside of what the jvm provides

so there aren't, I dunno instruction extensions or something that java compilers know about

but there have been changes to the jvm that required java compiler changes, that also required clojure compiler changes, and the clojure compiler changes lagged some amount of time (I think the main thing I am thinking about is default methods in interfaces)

there have been features where clojure doesn't implement java semantics (java varargs, I haven't done a lot interop recently so this might actually have been changed around 1.12), where clojure just sort of exposed the raw jvm behavior, and it trips people up

clojure implements it's own method resolution for determining what methods it can call for interop, and it is kind of harry, and has broken in the past on new jvms where sort orders of things have changed

Alex Miller (Clojure team) 2026-09-14T21:17:25.658269Z

mostly agree with all that, was just going to say that method resolution for invocation is probably the biggest part where we are kind of doing the same thing as the Java compiler

Alex Miller (Clojure team) 2026-09-14T21:18:42.435479Z

I'm not sure what you're thinking about that actually broke. things like bridge methods, or default/static methods in interfaces were new things to be aware of

Alex Miller (Clojure team) 2026-09-14T21:19:36.522169Z

certainly the null stuff coming down the pike in Valhalla has the potential to affect us

there was something, I may be conflating a few things

Alex Miller (Clojure team) 2026-09-14T21:21:31.640249Z

our bytecode emitting is implemented by ASM (which was also used by and tightly coupled to the Java compiler team), so we are jointly leaning on semantics embedded in that library like emitting exception handling code

Nice. Thank you both for this information. I get a lot of questions about why jank generates C++ instead of LLVM IR and the ultimate answer is that jank would need to implement huge parts of a C++ compiler in order to get its C++ semantics into LLVM IR, which is just not worthwhile for anybody. But I would like to be able to draw a comparison as to why Clojure doesn't need to generate Java to achieve its goals and can instead generate JVM bytecode, due to the closeness in semantic level. It sounds like they're not exactly 1:1, so there is some duplication (i.e. method resolution), but that I am largely correct in my reasoning.

https://clojurians.slack.com/archives/C03S1KBA2/p1537369009000100 maybe what I was thinking of, but that is just non-determinism in method resolution, not breaking between jvm versions

Alex Miller (Clojure team) 2026-09-14T21:35:20.526289Z

Yeah, that hasn't been fixed yet :)

😱 1

I see we have :excess and :missing on master -- are we close to an Alpha 7 release, so we can try these out?

Alex Miller (Clojure team) 2026-09-14T22:18:08.168439Z

Yes

👍🏻 1