babashka

hlship 2026-02-11T19:32:57.551289Z

I was attempting to use org.clojure/core.cache, but got a runtime error for java.lang.ref.SoftReference ; is this something (SoftReference) that can be added to Babashka?

✅ 1
borkdude 2026-02-13T10:49:14.384629Z

@seancorfield the issue is that protocols in SCI aren't invoked via interop but via their proper protocol function names.

user=> (defprotocol Foo (foo [_]))
Foo
user=> (defrecord Dude [] Foo (foo [_] 1))
user.Dude
user=> (.foo (->Dude))
java.lang.NoSuchFieldException: foo [at <repl>:1:1]

borkdude 2026-02-13T10:49:41.802669Z

I could perhaps fix that, but doesn't seem to gain that much since it's not idiomatic to write it like (.foo ..) anyway?

borkdude 2026-02-13T10:52:20.026589Z

I let an LLM write a more idiomatic version of the tests and those all pass

borkdude 2026-02-13T10:55:34.842469Z

Hmm, I do notice it skipped a bunch of .has etc tests. I'll try to do a more faithful translation of the existing tests. The wrapped tests run as is

borkdude 2026-02-13T11:17:02.071189Z

ok, now I started from scratch and guided claude code how to fix the tests:

All 19 tests pass with 297 assertions, 0 failures, 0 errors. The only change needed to the test file was:

  1. Remove the cache type imports (loaded from source .clj now, not needed)
  2. :reload-all → :reload
  3. .lookup → lookup, .has? → has?, .hit → hit (protocol functions instead of Java method calls)

  And we fixed babashka itself by adding java.lang.Object proxy support in src/babashka/impl/proxy.clj.

seancorfield 2026-02-13T14:38:25.226829Z

Yeah, I don't know why @fogus specifically tests for the interop version as well as the protocol version in core.cache. Feels like an implementation detail to me, but core.cache has been around for a very long time so maybe that dates back to wanting to test the mechanics of it?

borkdude 2026-02-13T14:40:57.375089Z

no sweat, I think bb has enough coverage in the adapted tests

fogus (Clojure Team) 2026-02-13T17:52:44.780369Z

Most likely any odd tests were from long ago when I was testing something odd… what that may have been has been lost to time.

borkdude 2026-02-11T19:35:14.648509Z

I think we can add it but looking at the source of core.cache, I think we'll hit another limitation with deftype + Java interfaces. There's also a workaround for this. Perhaps the maintainer of core.cache will be open to making it bb compatible, or we could just add core.cache to bb if there's enough demand for it. What is your use case?

hlship 2026-02-11T20:02:28.198599Z

Just normal caching of expensive to compute values. Since it's non-trivial, it's probably not a good fit. I'm using Babashka to fire up a relatively long-running web service and doing some expensive calculations such as diffing text - that feels like an edge case. I just built a simple cache around an Atom instead. core.cache is oriented towards very long lived high throughput services.

borkdude 2026-02-11T20:03:40.080559Z

> Since it's non-trivial, it's probably not a good fit. Can you explain this sentence a bit more?

hlship 2026-02-11T20:04:26.019029Z

Since it is not trivial to extend Babashka to support core.cache, and an edge case for Babashka usage, I don't think you should do anything.

hlship 2026-02-11T20:07:54.836749Z

This is all related to my use of Datastar with Babashka. With my fairly large UI, I'm finally hitting points where I notice Babashka performance vs. Clojure performance and I'm looking for optimizations. Again, I'm pushing things well beyond the common definition of scripting.

borkdude 2026-02-11T20:08:38.948599Z

I didn't know you were using bb with datastar, that's cool :) are you using their official clojure sdk with bb?

hlship 2026-02-11T20:15:11.736739Z

yes. I mostly develop in Clojure with Cursive, but the same code runs fine (but a bit slower) as Babashka. I'm using their http-kit based adapter.

hlship 2026-02-11T20:15:31.764819Z

https://github.com/hlship/dialog-tool

borkdude 2026-02-11T20:17:09.456789Z

great :)

borkdude 2026-02-11T22:28:51.954509Z

$ clj -M:babashka/dev -cp src/main/clojure -e "(require '[clojure.core.cache :as cache])  (def C1 (cache/fifo-cache-factory {:a 1, :b 2})) (def C1' (if (cache/has? C1 :c)
               (cache/hit C1 :c)
               (cache/miss C1 :c 42))) C1'"
{:a 1, :b 2, :c 42}

hlship 2026-02-11T22:39:38.321079Z

I was using the clojure.core.cache.wrapped namespace and that's where I hit the failure. I'm actually good with what I have; again, my process is long-lived by script standards, but short-lived by service standards, and there's a reasonable point where I can clear the cache.

borkdude 2026-02-11T22:40:01.284959Z

I know. I just couldn't resist

hlship 2026-02-11T22:40:07.788419Z

I know that feeling.

borkdude 2026-02-11T22:40:09.089939Z

wrapped would work too

hlship 2026-02-11T22:40:47.753239Z

Ah, I didn't see what you were doing. You just snuck this into dev didn't you?

borkdude 2026-02-11T22:41:04.530249Z

I only have it working on my local system

hlship 2026-02-11T22:41:20.971879Z

Well, I'll loop back after the next release ...

borkdude 2026-02-11T22:41:39.296629Z

it needs changes in core.cache which probably will never be accepted :)

borkdude 2026-02-11T22:42:26.021339Z

I could write a .bb only file that people could include in their own projects as a replacement

borkdude 2026-02-11T22:49:38.823479Z

$ clojure -M:babashka/dev -Sdeps '{:paths ["src/main/clojure" "src/test/clojure"] :deps {io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" :git/sha "dfb30dd"} org.clojure/test.check {:mvn/version "1.1.3"}}}' -m cognitect.test-runner -d src/test/clojure

Running tests in #{"src/test/clojure"}

Testing with Babashka 1.12.215-SNAPSHOT

Testing clojure.core.cache.wrapped-test
ttl test completed 2000000 calls in 3618 ms

Testing clojure.core.cache-test

Ran 21 tests containing 373 assertions.
0 failures, 0 errors.

seancorfield 2026-02-11T22:50:30.906019Z

core.cache maintainer here... what changes would be needed to support bb?

borkdude 2026-02-11T22:53:49.406999Z

This should now work with bb from development (`bash <(curl https://raw.githubusercontent.com/babashka/babashka/master/install) --dev-build --dir /tmp`): https://github.com/borkdude/core.cache/commit/33fcb3006bba2d67e73ddb97718831824ae6bdfe

borkdude 2026-02-11T22:54:48.344339Z

@seancorfield I had to change the deftype stuff to proxy and create my own factory functions so you don't create cache types with Foo. but rather with ->Foo. I put it all in different .bb files to not interfere with the existing impl

seancorfield 2026-02-11T22:59:47.757789Z

Ah, that is pretty extensive, and I would imagine would affect performance if it was used on the mainline Clojure version... ...and I guess the changes are too extensive to hide behind reader conditionals.

borkdude 2026-02-11T23:02:54.206029Z

I don't think it would affect performance in Clojure that much. Foo. vs ->Foo. shouldn't matter that much. The proxy trick is only necessary to make the caches behave like maps (lookup, etc). If we dropped that restriction for bb and people would only use the protocol, the diff would be smaller. But I guess people do use caches as maps

seancorfield 2026-02-11T23:03:34.500269Z

Yeah, I'd say most of the usage out there is cache-as-map TBH.

borkdude 2026-02-11T23:04:03.007379Z

I'm fine keeping this in a branch somewhere until a next person asks about this and not doing anything with it at the moment

borkdude 2026-02-11T23:10:34.752429Z

I did detect a small bug in SCI when implementing this and I added the SoftReference class so it's a good experiment anyway

seancorfield 2026-02-11T23:18:53.960329Z

Looking at your .bb version side-by-side with the .clj version, I realized that FnCache is broken (it uses BasicCache internally instead of FnCache).

👍 1
borkdude 2026-02-11T23:19:24.210219Z

broken in clj or bb or both?

seancorfield 2026-02-11T23:19:47.318299Z

Both, since the original is broken.

borkdude 2026-02-11T23:20:09.473249Z

k

seancorfield 2026-02-11T23:24:55.741279Z

I was curious if the Babashka version would run as Clojure, so I replaced the .clj files in core.cache with the .bb versions (extension changed) and tried to run the tests: Unexpected error (ClassCastException) macroexpanding clojure.core/proxy at (clojure/core/cache.clj:125:1). class clojure.lang.Var cannot be cast to class java.lang.Class (clojure.lang.Var is in unnamed module of loader 'app'; java.lang.Class is in module java.base of loader 'bootstrap')

borkdude 2026-02-11T23:25:43.321869Z

interesting :)

borkdude 2026-02-11T23:26:38.653589Z

I can take a look at this discrepancy tomorrow

seancorfield 2026-02-11T23:39:50.492879Z

You can't proxy a protocol maybe? Only class or interface.

borkdude 2026-02-12T08:48:16.148199Z

I think you're right...

;; Define a protocol
(defprotocol Greeter
  (greet [this]))

;; Try to use the protocol directly in proxy
(def x
  (proxy [Runnable Greeter] []
    (run []
      (println "Running from proxy"))
nil
user=> user=> user=>
    (greet []
      (println "Hello from protocol inside proxy"))))
Greeter
user=> user=> user=> Unexpected error (ClassCastException) macroexpanding proxy at (REPL:2:3).

borkdude 2026-02-12T09:41:32.297059Z

ah, but this works!

(defprotocol Greeter
  (greet [this]))

(def x
  (proxy [Runnable user.Greeter] []
    (run []
      (println "Running from proxy"))
    (greet [] (println "Hello from protocol inside proxy"))))

borkdude 2026-02-12T10:07:49.502219Z

Hmm, perhaps I can special-case implementing custom maps in deftype so it will be compatible with bb...

borkdude 2026-02-12T10:08:05.129099Z

similar to the proxy case

seancorfield 2026-02-12T14:22:16.647159Z

Thanks. Will take a look tomorrow probably.

borkdude 2026-02-12T14:26:09.900519Z

no need. I already got it working in bb without any change to core.cache now :)

borkdude 2026-02-12T14:26:26.966239Z

(locally)

borkdude 2026-02-12T20:57:34.106849Z

The bb dev build should now support core.cache from source, no changes in source.

bash <(curl )  --dev-build --dir /tmp
Try it with:
$ /tmp/bb -Sdeps '{:deps {org.clojure/core.cache {:mvn/version "1.1.234"}}}' -e "(require '[clojure.core.cache :as cache]) (def c (cache/ttl-cache-factory {:token \"abc123\"} :ttl 1000)) (println (cache/has? c :token)) (Thread/sleep 1000)  (println (cache/has? c :token))"
;; true
;; false

🎉 3
seancorfield 2026-02-13T02:10:52.464059Z

Looks good. I assume this is expected if I try to run the tests with bb:

ERROR in (test-soft-cache-ilookup) (/home/sean/oss/core.cache/src/test/clojure/clojure/core/cache_test.clj:442)
that the SoftCache can .lookup