babashka 2025-06-04

Searching through history, I see a couple of posts from people being unable to run something because of things that core.cache uses. I'm hitting a similar issue - I'm trying to use a library that depends upon memoize that depends upon cache and I'm getting Unable to resolve classname: java.lang.ref.SoftReference. Any chance this could be added? Happy to be told there's another way 🙂

I'd be happy to add it if it would make the complete scenario of what you're trying to do work. What is this complete scenario?

Using randomseed-io/phone-number to parse over 100,000 phone numbers for validity.

Thus, reading from the db (thanks mysql pod), parsing each number in turn for compliance and country specific formatting, then saving somewhere else.

it seems that this library depends on a lot of Java stuff that's not available in bb, probably?

io.randomseed/phone-number 8.13.6-3
  . com.googlecode.libphonenumber/geocoder 2.200
    . com.googlecode.libphonenumber/libphonenumber 8.13.6
    . com.googlecode.libphonenumber/prefixmapper 2.200
  . com.googlecode.libphonenumber/carrier 1.190
    . com.googlecode.libphonenumber/libphonenumber 8.13.6
    . com.googlecode.libphonenumber/prefixmapper 2.200
  . malabarba/lazy-map 1.3
  . com.googlecode.libphonenumber/libphonenumber 8.13.6
  . com.googlecode.libphonenumber/prefixmapper 2.200
    . com.googlecode.libphonenumber/libphonenumber 8.13.6
  . org.clojure/core.memoize 1.0.257
    . org.clojure/core.cache 1.0.225
      . org.clojure/data.priority-map 1.1.0
  . trptr/java-wrapper 0.2.3

I've pulled in libphonenumber as a dep, but doing the checking falls over immediately with the cache/soft-reference missing class.

I could just do this in plain old clj I guess, but I was trying to see if I could do this faster in bb.

this is because it didn't reach the Java lib problem yet, it first stumbles over the Softref thing missing. The next error you'll see is:

$ clj -M:babashka/dev -Sdeps '{:deps {io.randomseed/phone-number {:mvn/version "8.13.6-3"}}}' -e "(require '[phone-number.core :as phone])"
----- Error --------------------------------------------------------------------
Type:     clojure.lang.ExceptionInfo
Message:  defrecord/deftype currently only support protocol implementations, found: clojure.lang.ILookup

core core/cache.clj

I could add core.cache + core.memoize as built-ins in bb which makes sense since it would enable running more libraries but then you would still hit the Java class problem e.g. here: https://github.com/randomseed-io/phone-number/blob/9ae592c0517a92d66534f0f62c291b21f02be58e/src/phone_number/locale.clj#L14

np, I'll switch to clj

so yeah in this case it's better to just use clj

What's happening here?

$ bb -m cli.foo
2025-06-04T17:23:20.132Z alex DEBUG [cli.foo:5] - x
$ bb -m cli.foo
----- Error --------------------------------------------------------------------
Type:     clojure.lang.ExceptionInfo
Message:  Could not resolve symbol: log/set-min-level!
Data:     {:type :sci/error, :line 4, :column 1, :file ".../cli/foo.clj", :phase "analysis"}
Location: .../cli/foo.clj:6:3
Phase:    analysis

----- Context ------------------------------------------------------------------
2:   (:require [taoensso.timbre :as log]))
3: 
4: (defn -main []
5:   (log/debug "x")
6:   (log/set-min-level! :error)
     ^--- Could not resolve symbol: log/set-min-level!
7:   (log/debug "x"))

----- Stack trace --------------------------------------------------------------
cli.foo/fn - .../cli/foo.clj:6:3
clojure.core/fn             - <built-in>
cli.foo    - .../cli/foo.clj:4:1
clojure.core/defn           - <built-in>
cli.foo    - .../cli/foo.clj:4:1
cli.foo    - .../cli/foo.clj:4:1
user                        - <expr>:1:10
Why is it that I can execute this fine when doing it interactively through a bb nrepl-server but it doesn't work when calling the main fn?

can you give me the text of the entire script?

(ns cli.foo
  (:require [taoensso.timbre :as log]))

(defn -main []
  (log/debug "x")
  (log/set-min-level! :error)
  (log/debug "x"))

I think in the nREPL in bb at least this doesn't work either: (taoensso.timbre/set-min-level! :error) since that var probably doesn't exist in bb.

(get (ns-publics 'taoensso.timbre) 'set-min-level!)

you can set the level with this:

(ns dude
  (:require [taoensso.timbre :as log]))

(defn -main []
  (log/debug "x")
  (log/merge-config! {:min-level :error})
  (log/debug "x"))

Hmm, maybe I tried it in a Clojure nREPL and got them mixed up. Could you explain why set-min-level! isn't available but merge-config! is? It's a little surprising to me. I guess to make a lib bb-compatible you expose some specific vars from the lib, but not all?

timbre is a very non-typical library with lots of macros and dynamic vars so it's complicated to make it work in bb. at the time (4 years ago) I only did the work to make the most used functions/macros work in bb

(def timbre-namespace
  (assoc (make-ns 'taoensso.timbre tns ['trace 'tracef 'debug 'debugf
                                        'info 'infof 'warn 'warnf
                                        'error 'errorf
                                        '-log! 'with-level
                                        'spit-appender '-spy 'spy
                                        'color-str])
         'log! (sci/copy-var log! tns)
         '*config* config
         'swap-config! (sci/copy-var swap-config! tns)
         'merge-config! (sci/copy-var merge-config! tns)
         'set-level! (sci/copy-var set-level! tns)
         'println-appender (sci/copy-var println-appender tns)
         '-log-and-rethrow-errors (sci/copy-var -log-and-rethrow-errors tns)
         '-ensure-vec (sci/copy-var encore/ensure-vec tns)))
we could easily add the function you're missing though

So there's no easy way to really tell if you're running into this sort of thing, right? Kind of just have to see such a surprising result and then look in the bb code to see if the var has copy-var called on it?

It's no big deal to use merge-config! here instead of the set-min-level!, I'm just trying to understand the how to go about it if I run into a similar situation in the future.

we can add set-min-level, makes sense to add it. I'll try to do it now

Maybe this would be a good candidate for a custom clojure-lsp linter.

or could this be a general type of linter in kondo itself?

hmm there is also a set-level! function which seems to do the same? it's available in bb now

yeah timbre seems to have a lot of ways to go about doing it

Intend to try out Telemere sometime anyway

I think set-level! should have been added as set-min-level! , probably I made a typo here, since set-level! doesn't exist in timbre

lol so I'm not the only one who makes typos huh

Okay borkdude, many thanks for your advice and direction.

It... looks familiar to me too.

apparently a rename:

98deeb73 [mod] [DEPRECATE] set-level! -> set-min-level!, with-level -> with-min-level

yep was just looking at that

so you don't make typos 😒

just not in this case ;)

I guess there could be some value in having an easy way to know if popular var disappears from some lib.

it didn't disappear but was deprecated

I hadn't seen that one yet.

anyway, fixed on master now

🙌 1