babashka

borkdude 2025-11-18T13:31:09.764829Z

If someone is up for some bytecode nerdery: reify in babashka is implemented using some pre-generated bytecode for each interface that is reify-able. That's done using the insn library in this https://github.com/babashka/babashka/blob/master/impl-java/build.clj and https://github.com/babashka/babashka/blob/master/impl-java/build/reify2.clj implementation. Currently it supports all vetted/curated interfaces. But when adding java.time.temporal.TemporalField the limitation is revealed that it doesn't support methods that return longs. Issue here: https://github.com/babashka/babashka/issues/1882 It's been a while since I looked at the insn code. For anyone who is really interested in bytecode with insn, this might be a fun issue to solve. LLM use is fine as long as you can fully explain the changes to me with words you understand yourself.

✅ 1
exitsandman 2025-11-18T20:50:53.236089Z

Am I missing something big or doesn't it just come down to extending the dispatches that already happen for int? I'll be home and testing any moment.

borkdude 2025-11-18T20:53:04.482359Z

that's certainly part of it

borkdude 2025-11-18T20:53:28.267939Z

if I remember correctly, it's also something with long being 2 things long so you have to adjust some index or so

borkdude 2025-11-18T21:03:51.923779Z

you can run clj -T:build install to install the adjustment. and then run clj -M:babashka/dev run bb from source with the new lib. My :babashka/dev alias is situated in my .clojure/deps.edn as:

{:aliases {:babashka/dev {:paths []
                          :deps {babashka/babashka {:local/root "/Users/borkdude/dev/babashka"}}
                          :main-opts ["-m" "babashka.main"]
                          }
where /Users/borkdude/dev/babashka is my local checkout of bb + git submodules

borkdude 2025-11-18T21:04:27.229629Z

here's info on how to clone the repo: https://github.com/babashka/babashka/blob/master/doc/build.md#clone-repository

borkdude 2025-11-18T21:04:40.053569Z

the clj -T:build install should be run in the java-impl dir

exitsandman 2025-11-18T21:04:51.396399Z

thanks

borkdude 2025-11-18T21:05:53.201739Z

thank you for taking a peek

exitsandman 2025-11-18T21:13:20.598259Z

I'm coming home to this lol: https://www.githubstatus.com/. I wonder if it's related to the Cloudflare outage or if it's its own thing.

borkdude 2025-11-18T21:49:35.112179Z

lol o no

exitsandman 2025-11-18T21:53:06.537359Z

oh well, looks like it's working now

exitsandman 2025-11-18T23:16:40.295079Z

it seems like I got it working

borkdude 2025-11-18T23:17:08.145369Z

wow nice!

exitsandman 2025-11-18T23:18:20.059949Z

are there more tests I can run to be sure? Also, fwiw I added the two required classes for the issue, should I push the PR with them as well or just the changes to the reify2 file?

borkdude 2025-11-18T23:20:15.664669Z

I don't know exactly what you mean, but just make the PR and then we can take it further

exitsandman 2025-11-18T23:20:34.909369Z

ok nice

exitsandman 2025-11-19T00:01:30.241179Z

alright, I was pushing my own thing, but I saw that you happen to have a similar branch which more or less does the same thing as mine, so I'm definitely missing something...

exitsandman 2025-11-19T00:01:53.359649Z

I'll make the PR against that branch anyway

borkdude 2025-11-19T03:52:59.523399Z

Oh please ignore most of what I had in that branch, t least the build.clj file is incorrect. You can borrow from it for your own PR.

borkdude 2025-11-19T09:16:11.972019Z

@doppiaelle1999 I see you opened a PR and then closed it. Are you going to open a new one with your stuff?

borkdude 2025-11-19T10:48:17.540029Z

It's fine to PR it against my branch if you want to. As long as it works, I'm happy :)

exitsandman 2025-11-19T19:16:53.687939Z

alright, I'll PR against master with a comment showcasing a generated class

borkdude 2025-11-19T19:18:16.884089Z

thank you for your persistence :)

exitsandman 2025-11-19T19:24:47.258979Z

done

borkdude 2025-11-19T19:25:09.257189Z

thanks!

borkdude 2025-11-19T19:39:18.623879Z

I have pulled and pushed your branch now as EvenMoreIrrelevance-master and added a test:

(deftest reify-temporal-field-test
  (bb nil "(def field
  (reify
    TemporalField
    (rangeRefinedBy [_ _temporal] (ValueRange/of 0 999))
    (getFrom [this temporal]  1)
    (adjustInto [this temporal value] temporal)))
  (prn (.rangeRefinedBy field nil)
  (.getFrom  field nil)
  (.adjustInto field (Instant/now) 1))"))
After installing the lib with clj -T:build install and then running the test with: I'm seeing this:
$ lein do clean, test :only babashka.reify-test/reify-temporal-field-test
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See  for further details.
Syntax error (VerifyError) compiling new at (babashka/impl/reify2.clj:99:15).
Bad local variable type
Exception Details:
  Location:
    babashka/impl/java/time/temporal/TemporalField.adjustInto(Ljava/time/temporal/Temporal;J)Ljava/time/temporal/Temporal; @23: lload_2
  Reason:
    Type top (current frame, locals[2]) is not assignable to long
  Current Frame:
    bci: @23
    flags: { }
    locals: { 'babashka/impl/java/time/temporal/TemporalField', 'java/time/temporal/Temporal', top, 'clojure/lang/IFn' }
    stack: { 'clojure/lang/IFn', 'babashka/impl/java/time/temporal/TemporalField', 'java/time/temporal/Temporal' }
  Bytecode:
    0000000: 2ab4 005e b200 48b9 0073 0200 c000 754e
    0000010: 2dc6 0013 2d2a 2b20 b800 adb9 00b0 0400
    0000020: c000 b2b0 bb00 7c59 12b4 b700 81bf
  Stackmap Table:
    full_frame(@36,{Object[#2],Object[#178],Top,Object[#117]},{})


Full report at:
/var/folders/j9/xmjlcym958b1fr0npsp9msvh0000gn/T/clojure-2143826522799449024.edn
Subprocess failed (exit code: 1)

exitsandman 2025-11-19T19:40:07.244379Z

let me see

borkdude 2025-11-19T19:40:27.352609Z

it doesn't even relate to the test, it manifests itself by just starting bb

exitsandman 2025-11-19T19:40:42.939149Z

strange, I had no issues

borkdude 2025-11-19T19:40:47.342159Z

I added java.time.temporal.TemporalField to the interfaces

borkdude 2025-11-19T19:40:59.043409Z

in babashka.impl.reify2.interfaces

borkdude 2025-11-19T19:44:40.463759Z

Maybe relevant, not sure if all JVMs verify the bytecode

$ java -version
java version "25" 2025-09-16 LTS
Java(TM) SE Runtime Environment Oracle GraalVM 25+37.1 (build 25+37-LTS-jvmci-b01)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 25+37.1 (build 25+37-LTS-jvmci-b01, mixed mode, sharing)

exitsandman 2025-11-19T19:45:39.267559Z

I had that running yesterday... let me check a thing

borkdude 2025-11-19T19:46:57.987539Z

maybe it's just junk in my target folder, let me test again

borkdude 2025-11-19T19:48:26.330529Z

ok the issue seems to be gone...

borkdude 2025-11-19T19:48:33.754669Z

no idea what it was

exitsandman 2025-11-19T19:48:44.505349Z

builds just fine here btw

borkdude 2025-11-19T19:49:32.182669Z

ok great, just a hiccup then :) I'll finish the test by fully qualifying stuff

exitsandman 2025-11-19T19:53:01.307219Z

btw I get this by setting method-slot to (count slots) (i.e. the logic before accounting for the wide longs), and loading (gen-reified TemporalField):

Exception Details:
  Location:
    babashka/impl/java/time/temporal/TemporalField.adjustInto(Ljava/time/temporal/Temporal;J)Ljava/time/temporal/Temporal; @23: lload_2
  Reason:
    Type top (current frame, locals[2]) is not assignable to long
  Current Frame:
    bci: @23
    flags: { }
    locals: { 'babashka/impl/java/time/temporal/TemporalField', 'java/time/temporal/Temporal', top, 'clojure/lang/IFn' }
    stack: { 'clojure/lang/IFn', 'babashka/impl/java/time/temporal/TemporalField', 'java/time/temporal/Temporal' }
  Bytecode:
    0000000: 2ab4 005e b200 48b9 0073 0200 c000 754e
    0000010: 2dc6 0013 2d2a 2b20 b800 adb9 00b0 0400
    0000020: c000 b2b0 bb00 7c59 12b4 b700 81bf     
  Stackmap Table:
    full_frame(@36,{Object[#2],Object[#178],Top,Object[#117]},{})
looks like the same exact error to me

borkdude 2025-11-19T20:09:17.785269Z

cool, now got this test working:

(deftest reify-temporal-field-test
  (let [s (bb nil "(def field
  (reify
    java.time.temporal.TemporalField
    (rangeRefinedBy [_ _temporal]
      (java.time.temporal.ValueRange/of 0 999))
    (getFrom [_ _temporal] 1337)
    (adjustInto [_ temporal value] temporal)))
  (prn (pr-str (.rangeRefinedBy field nil)
          (.getFrom field nil)
          (.adjustInto field (java.time.Instant/now) 1)))")]
    (is (str/includes? s "0 - 999"))
    (is (str/includes? s "1337"))
    (is (str/includes? s "java.time.Instant"))))

borkdude 2025-11-19T20:13:31.755759Z

now pushed impl.java 0.1.11 to clojars and bumped it in bb. CI running here: https://github.com/babashka/babashka/tree/EvenMoreIrrelevance-master

borkdude 2025-11-19T20:21:23.087829Z

looks like the test passed! === reify-temporal-field-test

borkdude 2025-11-19T20:21:42.061699Z

I'm going to study your solution a bit more and then I'll merge it. thanks a ton, this saved me a lot of time

borkdude 2025-11-19T22:24:18.190949Z

@doppiaelle1999 merged to master. thanks a bunch!