cljs-dev

borkdude 2026-05-20T14:04:22.313949Z

@dnolen improvements: https://github.com/clojure/clojurescript-site/pull/424

dnolen 2026-05-20T14:50:53.095429Z

@borkdude thanks, some minor code style requested around globals usage.

borkdude 2026-05-20T14:56:56.292359Z

Promise/resolve That surprises me. I thought this was only possible with aliases, not referred things. JVM Clojure doesn't let you do this with referred vars.

borkdude 2026-05-20T15:00:31.504269Z

And why (,log console) instead of (console/log ...) - seems the same scenario

dnolen 2026-05-20T15:01:38.909559Z

Not the same console is a singleton, vs type

borkdude 2026-05-20T15:03:00.354689Z

makes sense

borkdude 2026-05-20T15:03:26.715449Z

I like Promise/resolve better, just wasn't sure worked intentionally :)

borkdude 2026-05-20T15:04:54.728459Z

pushed

dnolen 2026-05-20T15:05:09.146279Z

Intentional all the global stuff was designed with the method syntax, static method stuff in mind

borkdude 2026-05-20T15:05:34.238189Z

πŸ‘

dnolen 2026-05-20T15:08:43.443259Z

Note that Promise works because the compiler knows all this stuff

dnolen 2026-05-20T15:09:25.025549Z

I refactored how externs type/tag processing works to disambiguate

borkdude 2026-05-20T15:11:14.418669Z

what's "all this stuff"? do you mean refer-globals or is there actually a list of "known" global types?

borkdude 2026-05-20T15:11:26.983299Z

(I expect the first)

dnolen 2026-05-20T15:12:03.274159Z

Yes if we can find it in the W3C externs. closure compiler provides this

borkdude 2026-05-20T15:13:25.526919Z

interesting

dnolen 2026-05-20T15:15:18.785409Z

For example (cljs.repl/doc Promise/resolve) should work

borkdude 2026-05-20T15:17:31.953719Z

nice

dnolen 2026-05-20T15:17:32.417699Z

Pretty much docs for a great chunk of the web is available at the REPL now

borkdude 2026-05-20T15:17:37.911999Z

cljs.user=> (cljs.repl/doc Promise/resolve)
-------------------------
resolve
([] [opt_value])
  /**
 * @param {VALUE=} opt_value
 * @return {RESULT}
 * @template VALUE
 * @template RESULT := type('Promise',
 *     cond(isUnknown(VALUE), unknown(),
 *       mapunion(VALUE, (V) =>
 *         cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),
 *           templateTypeOf(V, 0),
 *           cond(sub(V, 'Thenable'),
 *              unknown(),
 *              V)))))
 * =:
 */

dnolen 2026-05-20T15:17:48.920379Z

Yep

dnolen 2026-05-20T15:18:56.281459Z

But it works on singletons too I'm pretty sure?

dnolen 2026-05-20T15:19:06.747959Z

We'll resolve the type for console

dnolen 2026-05-20T15:19:44.272999Z

Or subtle crypto

borkdude 2026-05-20T15:20:00.478839Z

cljs.user=> (cljs.repl/doc console)
-------------------------
console
  /**
 * @type {!Console}
 * @suppress {duplicate}
 */
it works, but doesn't really tell me that much :)

dnolen 2026-05-20T15:21:43.797789Z

Ah right it would be nice if it worked for

dnolen 2026-05-20T15:21:54.458829Z

Console/.log

dnolen 2026-05-20T15:21:57.100039Z

It might

dnolen 2026-05-20T15:22:38.442819Z

That would be a nice one

borkdude 2026-05-20T15:22:38.541699Z

cljs.user=> (refer-global :only '[Console])
nil
cljs.user=> (cljs.repl/doc Console/.log)
WAR

borkdude 2026-05-20T15:22:50.360509Z

oops sorry:

WARNING: No such namespace: Console, could not locate Console.cljs, Console.cljc, or JavaScript source providing "Console" at line 1 <cljs repl>

borkdude 2026-05-20T15:23:05.258049Z

Console doesn't exist

dnolen 2026-05-20T15:23:34.052049Z

Then you could get doc for HTMLElement/.setAttribute

dnolen 2026-05-20T15:23:59.752089Z

Yeah this is a gap I didn't consider, but I think everything already there

dnolen 2026-05-20T15:58:18.642409Z

merged

πŸ‘ 1
dnolen 2026-05-20T19:29:11.291619Z

no deref on await, not gonna happen

πŸ‘ 3
dnolen 2026-05-20T03:27:33.933279Z

We should add that note as well. It can't mean anything in CLJS so perhaps this is ok.

shaunlebron 2026-05-20T16:06:02.013529Z

Just a heads-up, it looks like @john has been working on thread support and adding agents here: https://clojurians.slack.com/archives/C07UQ678E/p1772394837343389?thread_ts=1772392661.696179&amp;cid=C07UQ678E

dnolen 2026-05-20T16:08:50.875749Z

I've been following that, but I think that probably needs to start from the beginning w/ a rationale etc.

john 2026-05-20T17:14:03.183649Z

Hey Shaun, thanks for bring it up. cljs-thread is very much an experimental thing and y'all are welcome to use any part of it. But I'd recommend just internalizing the ideas in it and try to translate that into cljs native idioms where appropriate. cljs thread would be built differently if it was a native thing

john 2026-05-20T17:15:08.917769Z

I'll be licensing it under 0BSD with no copyright, so vendor in any line you want or just use the ideas where appropriate

john 2026-05-20T17:26:44.164369Z

I just don't understand cljs internals well enough to map it out. So I can't recommend bringing in any particular piece.

john 2026-05-20T17:27:01.522589Z

But as an abstraction it's all there

john 2026-05-20T17:29:34.661889Z

But relatedly - cljs-thread really makes it easy for you to do a datacenter-in-a-box type thing. Cljs is a pretty good candidate for that. Might want to keep your eye on that direction. I've got a clojure-like coming out soon that experiments in that direction.

shaunlebron 2026-05-20T17:30:30.448379Z

thanks, I’m only at the api level, just noticed the latest await function could conflict with agents if they were ever added, and wasn’t sure if that was gonna be a thing in the future, but I noticed you were trying it out

john 2026-05-20T17:31:18.099399Z

Pretty sure multi threading was never in scope for OG cljs

john 2026-05-20T17:31:24.195099Z

But it would be interesting

dnolen 2026-05-20T17:32:31.321939Z

to be clear I don't mean to say you need a rationale @john πŸ™‚ - rather if ClojureScript was going to assess this work or use it as a jumping off point - we should start with a rationale

john 2026-05-20T17:33:04.627289Z

For sure! Yeah, I'm not sure it's rational for cljs

dnolen 2026-05-20T17:33:10.418459Z

@shaunlebron it's not about agents really, but any real concurrency construct at all.

john 2026-05-20T17:33:13.216959Z

It's a big thing to bite off

john 2026-05-20T17:43:11.845489Z

It's also possible some wasm//js thing comes out in the future that obviates cljs-thread. So there's some reason to just waiting

john 2026-05-20T17:56:40.423089Z

Oh... One thing that I'm still confused about in my mind... Not sure if y'all have figured it out: I feel like promises should be derefable.... or some how married up to clojure semantics better... I've tried multiple experiments, none of which I fully trust yet. I feel like those semantics need simplification somehow but idk

john 2026-05-20T17:57:37.812529Z

And that seems related to the await question.

john 2026-05-20T17:59:51.433599Z

If we could somehow make promise interop cleaner, maybe that would relate to newer await semantics? IDK, I haven't focused on that in a while but it just seems messy to me

john 2026-05-20T18:15:17.295309Z

Oh also... cljs-thread's SAB work got externalized into EVE... right now, even has some of cljs-thread's machinery in it, to make it go, but the plan there was to then rebase cljs-thread with eve as a dep. But eve is going to have a "network mode." This makes your cljs-thread atom into a multi level LRU. So your atom is like 100MB in heap space, with eviction. Then GB of mmap'd memory in SABs. You can put your root pointer there or you can go one layer lower in the browser to like local-storage. But I use OPFS. You can use fast CAS and blob read/write in browsers with OPFS vs the other browser persistence layers. That's a three layer atom, where the two higher layers are just LRUs. So your memory is basically paged in by the os and most hot ops stay in heap space. But eve will have a network layer soon. You've got an atom server that acts as a signaling server. It only holds the root pointer and is designed to provide root pointer signaling to tens of thousands of peers in parallel. Peers are writing to whatever your favorite global blob store is. Then the OPFS becomes just another LRU layer and your base atom layer is the network. The base layer of your multi layer LRU atom is the one that holds the root pointer and all reads and writes still have to be coordinated from the base layer for it all to work.

john 2026-05-20T18:18:36.400109Z

And so I say all that to say that, because eve will be having actual network atoms in the near future, putting a queue in front of an eve network atom would turn it into a clojure agent. There will be a version of an eve agent, but it won't be really used for most things. For an agent you'd probably want dense storage on that agent. Datomic is literally an agent in the clojure/eve sense of things. So I'm not sure if I'll actually have an agent in eve

shaunlebron 2026-05-20T18:23:04.309429Z

re: deref => await, that’s a neat idea allowing async functions to deref a promise by emitting await

πŸ‘Ž 1
john 2026-05-20T18:30:16.638639Z

I gotta say though y'all... Being able to swap on an atom that doesn't actually fit in local memory, but all the semantics are still the same... That hits different.

john 2026-05-20T18:45:56.520739Z

In a swapping transaction, not all swappers look at the whole tree. So you can turn your memory model inside out and just LRU everything in just in time.

john 2026-05-20T18:46:38.512519Z

And it's only possible because of a combination of persistent data structures, MVCC and the atom model.

john 2026-05-20T18:47:42.989889Z

being immutable

john 2026-05-20T19:02:37.395519Z

You can have raspberry pis chewing through swaps on petabyte atoms, in pure clojure syntax. It's bonkers.

john 2026-05-20T20:02:39.894059Z

I'm calling this new clojure-like "ValueScript" πŸ™‚

john 2026-05-20T20:04:24.413799Z

It'll be the first language to have eve as a memory model, with epochal memory management

john 2026-05-20T20:05:23.629829Z

The whole runtime moves forward according to Clojure's epochal time model

john 2026-05-20T20:06:50.422999Z

And I consider it a "distributed language runtime" because the whole runtime need not be in local memory at one time.

john 2026-05-20T20:11:27.364309Z

It's basically Rich's mental model of time, as a distributed system, with a trick of turning the memory model inside out

john 2026-05-20T20:22:13.032239Z

I'm no computer scientist but it looks like as much of a "computer science discovery" as much as I've ever seen one. And I consider it Rich's discovery - I literally just tried to find the most efficient impl of Rich's concurrency ideas in CLJS and eve is what came out. It's a pretty direct mapping, IMO, and that's what you get. GC free, memory as a network cache cloud language thing. I've never seen anything like it before.

john 2026-05-20T21:11:27.977869Z

At least not before clojure. But with networked eve, it'll look just like clojure, but like the whole datacenter is in-language. Servers are threads. Parallel transductions, with transients and everything, over extensible data types, just works across serverless clusters. Clojure's semantics work perfectly in a distributed system.

dnolen 2026-05-20T03:28:01.223839Z

(No agents)