cljs-dev

borkdude 2025-06-17T10:26:04.900139Z

It seems CLJS is complaining about a dynamic var that's private being used in binding:

WARNING: var: sci.ctx-store/*ctx* is not public at line 21 /Users/borkdude/dev/babashka/sci/src/sci/impl/interpreter.cljc
WARNING: var: sci.ctx-store/*ctx* is not public at line 21 /Users/borkdude/dev/babashka/sci/src/sci/impl/interpreter.cljc
which in JVM Clojure is perfectly fine behavior. The use case in JVM Clojure for this is often to write macros like with-something that bind the (private) dynamic var for you, while not exposing the var directly as a public API

borkdude 2025-06-17T10:28:03.492439Z

Repro:

$ clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "RELEASE"}}}' -M -m cljs.main -re node
ClojureScript 1.12.42
cljs.user=> (ns foo)
WARNING: foo is a single segment namespace at line 1 <cljs repl>
nil
foo=> (def ^:dynamic ^:private *foo*)
#'foo/*foo*
foo=> (ns dude)
WARNING: dude is a single segment namespace at line 1 <cljs repl>
nil
dude=> (binding [foo/*foo* 10])
WARNING: var: foo/*foo* is not public at line 1 <cljs repl>
WARNING: var: foo/*foo* is not public at line 1 <cljs repl>
In the JVM:
$ clj
Clojure 1.12.1
user=> (ns foo)
nil
foo=>  (def ^:dynamic ^:private *foo*)
#'foo/*foo*
foo=> (ns dude)
nil
dude=>  (binding [foo/*foo* 10])
nil

dnolen 2025-06-17T13:14:01.760569Z

hrm - how does that work in Clojure? Old CLJS issue for sure

borkdude 2025-06-17T13:15:40.249189Z

I think clojure doesn't complain because (var foo/private-var) never complains

borkdude 2025-06-17T13:16:18.934319Z

no big issue, I'll just document in the docstring that this shouldn't be used directly and hide it from the API docs

borkdude 2025-06-17T13:19:39.082719Z

is private also used for optimizations in CLJS/closure? I guess not right? just something that only exists at compile time?

dnolen 2025-06-17T15:41:48.364019Z

so that's like some kinda of trick that the macro writer does?

dnolen 2025-06-17T15:42:04.402079Z

that a big no-no for DCE to use (var ...) like that.

borkdude 2025-06-17T15:46:52.469059Z

I'm not suggesting to do this in CLJS, I know it's not good for bundle size to use var. Just explaining how the Clojure (JVM) mechanism works. The CLJS compiler could just not warn for private access of dynamic vars in certain macros, not sure if that's the best solution.

borkdude 2025-06-17T15:47:11.236559Z

The binding macro generates a map with vars in JVM Clojure

dnolen 2025-06-17T16:06:02.342209Z

I think this is just a difference, not really interested in messing around here anymore

borkdude 2025-06-17T16:07:00.133329Z

understandable

dnolen 2025-06-17T16:08:24.320649Z

there is ^:cljs.analyzer/no-resolve - maybe that works for this pattern?

borkdude 2025-06-17T16:08:51.352849Z

do you mean in user space?

dnolen 2025-06-17T16:09:19.700399Z

it's just meta data you can put on any symbol

borkdude 2025-06-17T16:09:44.539979Z

sure. I thought this was an internal compiler convention, but if it's also public, I'm willing to use it

dnolen 2025-06-17T16:25:03.750009Z

it's an internal detail for sure - just not sure what you're trying to do so just throwing it out there

borkdude 2025-06-17T16:32:47.601049Z

I'm pretty sure it's a supported pattern in Clojure to write macros that use private vars without letting users use the private var directly, just don't remember the classic example in core itself. But no sweat, I solved it another way now

dnolen 2025-06-17T16:42:53.175859Z

yes I know it's supported but I don't see any good way to make it work

dnolen 2025-06-17T16:44:20.820429Z

the problem is you can't use this specific trick from Clojure since there are no real vars, and I don't really want to add something just for this case.

borkdude 2025-06-17T16:44:31.449839Z

no worries, there are more ways to indicate that this var shouldn't be used directly.

👍🏽 1