@dnolen improvements: https://github.com/clojure/clojurescript-site/pull/424
@borkdude thanks, some minor code style requested around globals usage.
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.
And why (,log console) instead of (console/log ...) - seems the same scenario
Not the same console is a singleton, vs type
makes sense
I like Promise/resolve better, just wasn't sure worked intentionally :)
pushed
Intentional all the global stuff was designed with the method syntax, static method stuff in mind
π
Note that Promise works because the compiler knows all this stuff
I refactored how externs type/tag processing works to disambiguate
what's "all this stuff"? do you mean refer-globals or is there actually a list of "known" global types?
(I expect the first)
Yes if we can find it in the W3C externs. closure compiler provides this
interesting
For example (cljs.repl/doc Promise/resolve) should work
nice
Pretty much docs for a great chunk of the web is available at the REPL now
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)))))
* =:
*/Yep
But it works on singletons too I'm pretty sure?
We'll resolve the type for console
Or subtle crypto
cljs.user=> (cljs.repl/doc console)
-------------------------
console
/**
* @type {!Console}
* @suppress {duplicate}
*/
it works, but doesn't really tell me that much :)Ah right it would be nice if it worked for
Console/.log
It might
That would be a nice one
cljs.user=> (refer-global :only '[Console])
nil
cljs.user=> (cljs.repl/doc Console/.log)
WARoops sorry:
WARNING: No such namespace: Console, could not locate Console.cljs, Console.cljc, or JavaScript source providing "Console" at line 1 <cljs repl>Console doesn't exist
Then you could get doc for HTMLElement/.setAttribute
Yeah this is a gap I didn't consider, but I think everything already there
merged
no deref on await, not gonna happen
We should add that note as well. It can't mean anything in CLJS so perhaps this is ok.
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&cid=C07UQ678E
I've been following that, but I think that probably needs to start from the beginning w/ a rationale etc.
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
I'll be licensing it under 0BSD with no copyright, so vendor in any line you want or just use the ideas where appropriate
I just don't understand cljs internals well enough to map it out. So I can't recommend bringing in any particular piece.
But as an abstraction it's all there
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.
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
Pretty sure multi threading was never in scope for OG cljs
But it would be interesting
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
For sure! Yeah, I'm not sure it's rational for cljs
@shaunlebron it's not about agents really, but any real concurrency construct at all.
It's a big thing to bite off
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
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
And that seems related to the await question.
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
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.
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
re: deref => await, thatβs a neat idea allowing async functions to deref a promise by emitting await
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.
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.
And it's only possible because of a combination of persistent data structures, MVCC and the atom model.
being immutable
You can have raspberry pis chewing through swaps on petabyte atoms, in pure clojure syntax. It's bonkers.
I'm calling this new clojure-like "ValueScript" π
It'll be the first language to have eve as a memory model, with epochal memory management
The whole runtime moves forward according to Clojure's epochal time model
And I consider it a "distributed language runtime" because the whole runtime need not be in local memory at one time.
It's basically Rich's mental model of time, as a distributed system, with a trick of turning the memory model inside out
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.
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.
(No agents)