cljs-dev

neumann 2026-06-03T20:39:14.795159Z

It seems like there should be a way to solve this problem using a core function/macro in CLJS without needing goog.object. Perhaps unchecked-get (or something similar) should become part of the ClojureScript core API?

neumann 2026-06-03T20:40:03.010839Z

@borkdude Does squint have built-in for this?

Harold 2026-06-03T20:46:49.030869Z

cljs.user> (aget #js{"foo" "bar"} "foo")
"bar"

👎 1
borkdude 2026-06-03T20:49:13.483379Z

In CLJS I use unchecked-get or aget . In squint you can just use get

neumann 2026-06-03T20:50:38.585249Z

@dnolen Any reason why unchecked-get shouldn't become "official" at this point in time?

neumann 2026-06-03T20:51:08.320869Z

Since https://clojurescript.org/news/2017-07-14-checked-array-access talks about avoiding aget.

borkdude 2026-06-03T20:51:44.938619Z

I know, but it works well and will continue to work well

borkdude 2026-06-03T20:52:52.852439Z

I read the objection in the blog post. unchecked-get it is then

borkdude 2026-06-03T20:53:07.348349Z

which is not public API :)

neumann 2026-06-03T20:53:16.711299Z

Yes. Exactly.

neumann 2026-06-03T20:53:25.174279Z

> In the relatively few places where it is not (in highly performance-critical areas in the standard library implmentation), the compiler makes use of a new internal unchecked-get macro to get the job done. > > We’d encourage you to revise code you control to to ensure that the aget and aset are used only for array access, and to consider using the facilities in goog.object (either directly, or indirectly via a library such as https://github.com/binaryage/cljs-oops) to access object properties.

borkdude 2026-06-03T20:53:46.288449Z

yeah I've used goog.object too a lot

borkdude 2026-06-03T20:54:05.432009Z

but I don't always want to pull that in

neumann 2026-06-03T20:54:48.447789Z

Exactly!

neumann 2026-06-03T20:55:18.015299Z

We've had unchecked-get for 9 years. Time to make it official? Or define an official thing?

borkdude 2026-06-03T20:56:23.207979Z

(obj-get ...) (obj-set! ... ...) would be nice additions

borkdude 2026-06-03T20:56:36.013549Z

I'm sure there's JIRA issues for it

borkdude 2026-06-03T20:59:46.306609Z

This also works in JS:

(doto #js {:a 1}  (js/Reflect.set "a" 2))
=> #js {:a 2}
(js/Reflect.get #js {:a 1} "a") => 1

neumann 2026-06-03T21:00:22.874749Z

Looks like the work for unchecked-get was done on https://clojure.atlassian.net/browse/CLJS-2198

borkdude 2026-06-03T21:01:56.300669Z

I've never seen the CLJS compiler complain about checked array access in any of my projects, maybe that flag isn't used a lot?

neumann 2026-06-03T21:15:08.920289Z

Personally, I always used aget, and after that change, and went back and changed some of my browser-deployed code to use clj-oops. I'd love a built-in.

👍 2
borkdude 2026-06-03T21:20:29.791429Z

I guess this would work well too

(defn oget [obj x] (js* "(~{}[~{}])" obj x))

dnolen 2026-06-03T22:02:11.862609Z

aget is for arrays like Clojure - unchecked-get is just a lower level thing which, no reason to use it except for performance.

dnolen 2026-06-03T22:02:23.949069Z

GCL is more or less the standard library, even more so now that we forked it.

dnolen 2026-06-03T22:03:23.619119Z

I just use goog.object - or newer Object methods in all cases.

dnolen 2026-06-03T22:09:33.819169Z

unchecked-get is just way too long of a name for a normal pattern, and it's name more or tells you it's a special case. gobj/get is shorter

2026-06-03T22:09:38.972459Z

is there a reason get can't be extended to work like this?

dnolen 2026-06-03T22:10:00.606439Z

it's impossible to detect object cases

dnolen 2026-06-03T22:10:27.889329Z

whatever we're going to do it's not going to involve get

👍 1
dnolen 2026-06-03T22:10:57.207779Z

the other thing is that generally you will want more complicated object access patterns

dnolen 2026-06-03T22:11:30.950969Z

GCL has a bunch of stuff w/ a eye for performance w/o bringing a whole bunch of unrelated code to accomplish that.

neumann 2026-06-03T22:14:48.799989Z

I've had the use case come up enough times in my own code that I'd love to have an object get that didn't require me to pull in GCL.

neumann 2026-06-03T22:16:05.847019Z

For me, at least, it feels like a missing piece of JS interop. It's inaccessible in core CLJS.

👍 2
Harold 2026-06-03T22:18:27.293619Z

"pulling in GCL" probably isn't as heavy as it feels, goog.object/get compiles to the exact things mentioned in the original post: https://github.com/google/closure-library/blob/b312823ec5f84239ff1db7526f4a75cba0420a33/closure/goog/object/object.js#L349-L354

neumann 2026-06-03T22:18:45.525379Z

I think @nbtheduke's question is the typical question I see: What's the interop form for foo[bar]?

neumann 2026-06-03T22:20:29.608879Z

It feels especially strange to me because foo["bar"] has language-level support via (.-bar foo).

👍 1
borkdude 2026-06-03T22:22:02.413949Z

I guess people just want something like unchecked-get but public and blessed. I'd like it too.

2026-06-03T22:22:08.486429Z

yes, that is my point

borkdude 2026-06-03T22:23:30.117169Z

Perhaps from the maintainer's point of view I get it: there's other patterns like getting stuff in nested objects that you would often need too, so it might be a slippery slope and goog.object already has a bunch of that stuff

2026-06-03T22:24:00.929099Z

compare with fennel (clojure-like compiling to lua), where (.bar foo) becomes foo.bar and (. foo bar) becomes foo[bar]

borkdude 2026-06-03T22:24:38.830349Z

Perhaps some of goog.object can be auto-referred (and maybe renamed) and if not used, it will be optimized away?

2026-06-03T22:29:45.091719Z

for the time being, i'll rely on unchecked-get as it directly compiles to what i want

👍 1
2026-06-03T22:33:49.148839Z

to veer wildly into early solutions lol, may i suggest (.- foo bar) as it currently doesn't compile and imo is the natural extension of the dot dash syntax

neumann 2026-06-03T22:38:13.445719Z

Here's the discussion where @pez ran into issues. It was a problem with "-", but also the different, slightly incompatible ways. https://clojurians.slack.com/archives/C03S1L9DN/p1755155632719919

2026-06-03T22:42:32.947399Z

oof that's rough

dnolen 2026-06-03T22:42:38.767319Z

"pulling in GCL" is the wrong way to think about, in reality using anything from cljs.core involves a lot more pulling, GCL is tree-shaking friendly, cljs.core not so much

dnolen 2026-06-03T22:46:19.661049Z

property access is for web stuff, GCL data types, and CLJS data types. Stuff that Closure will see. "data" objects i.e. JSON things need goog.object

dnolen 2026-06-03T22:47:21.012659Z

people try all kinds of things, but IMO if you just stick w/ goog.object/get for JSON and property access only for deftype and known Web APIs you can avoid a lot of trouble.

👍 1
dnolen 2026-06-03T22:51:05.593869Z

I'm not saying we shouldn't work on this - but that's approach I've used for the past 9 years or so and it's relatively headache free, I type a few more characters but I don't really think about this problem at all.

dnolen 2026-06-03T22:51:24.526999Z

any proposal needs to be simpler

2026-06-03T22:51:30.732749Z

how receptive would you be to expanding (or accepting a PR to expand) the clojurescript site to describe the core team's stance/suggestions?

2026-06-03T22:51:41.940489Z

i read every page and it didn't cover this which is why i came here

dnolen 2026-06-03T22:52:17.195009Z

I mean the first this is foo[x] in JS is completely ambiguous

dnolen 2026-06-03T22:52:28.044849Z

if foo is an array and x is "10000" what happens

2026-06-03T22:52:35.499929Z

you get undefined

dnolen 2026-06-03T22:52:49.937929Z

and what if you assign

dnolen 2026-06-03T22:52:59.564679Z

you get sparse array, all kinds of weird stuff happens

2026-06-03T22:53:33.974419Z

well, we're not discussing assignment

dnolen 2026-06-03T22:53:46.428119Z

my point is that the JS overloaded []

dnolen 2026-06-03T22:53:56.573869Z

historically people (ab)used aget aset together

2026-06-03T22:55:32.373529Z

sure, js has made some poor decisions lol

dnolen 2026-06-03T22:56:47.437089Z

In any case that's how we ended up here - people abused this pattern in CLJS - new names are awkward. Thus the above recommendations

dnolen 2026-06-03T22:58:47.973069Z

Making what we recommend clearer is a good idea of course.

👍 2
2026-06-03T22:59:53.757939Z

right now there's no documented method outside of the news post linked above to perform an object get with a variable key (`foo[bar]`, the way to do it in vanilla javascript), so outside of foundational language changes, i'm looking to ease future pain for other folks with documentation

neumann 2026-06-03T23:00:46.511019Z

The way I'm thinking about it is from an interop point of view. JS has all sorts of ugly and nasty behavior, but if I need to construct it, then I need an interop form/macro. Right now, there is no clear way to construct obj[key] from CLJS. People in the community keep recommending unchecked-get.

👍 2
2026-06-03T23:00:49.680789Z

pointing devs to the GCL documentation only does so much because you don't know what you don't know lol

neumann 2026-06-03T23:02:03.669069Z

I actually want the exact semantics of the host language. I don't want something that tries to protect me from it, because I'm trying to do interop.

👍 2
2026-06-03T23:02:26.286229Z

i'm willing to write the documentation into the Host Interop section, it's currently sparse compared to the extended docs for Clojure and could use some love

dnolen 2026-06-03T23:03:41.730409Z

again if people want to rely on the details then aset suffices no? but again just uninteresting to make this recommendation to me.

dnolen 2026-06-03T23:04:06.340879Z

again "I want the same exact semantics of the host language" is not what everyone wants

2026-06-03T23:04:20.403329Z

i thought aset was changed to only work with arrays, which is why i didn't reach for it

dnolen 2026-06-03T23:04:20.486489Z

some people are writing mostly CLJS and they keep the stuff at the edges

dnolen 2026-06-03T23:04:37.363839Z

aset producing a warning not an error and you can suppress it like any other warning

dnolen 2026-06-03T23:08:21.714439Z

It's discourages the pattern from libraries, but I don't really a see a problem with that, the bar for libraries is higher in the interop area because of tree-shaking, perf etc.

dnolen 2026-06-03T23:08:33.934059Z

for apps, doesn't matter that much other than philosophy

2026-06-03T23:09:40.683329Z

if you don't believe this is a worthwhile feature of javascript to support (in syntax or blessed function), then i will drop it and focus on improving the documentation

dnolen 2026-06-03T23:09:42.912399Z

I'd be ok w/ documentation talking about goog.object/get but also pointing out that in JS there are only really objects in the early spec, unlike Clojure - so you could use aget and you could suppress the warning if that's desired for whatever reason.

2026-06-03T23:10:30.620209Z

what do you mean by "early spec"?

dnolen 2026-06-03T23:10:44.493649Z

early JS spec. the other thing that is worth pointing out is that none of this addresses the biggest problem

dnolen 2026-06-03T23:11:17.754569Z

i.e. if you use prop access on JSON, or you use aget alternative on deftype - both will lead to a broken build.

dnolen 2026-06-03T23:13:54.350649Z

so if we do add something perhaps a documentation refresh is in order here - and I'm happy to assist and write something etc.

2026-06-03T23:14:14.842629Z

you mean JSON.parse output? or something else

dnolen 2026-06-03T23:15:15.015909Z

any JS value the Closure Compiler will never see the definition of has this problem, but it rears its head most often with APIs that take JSON/like values

neumann 2026-06-03T23:52:19.611149Z

I do agree with improving the docs and putting the nuances in the official reference. It's good to know that the aget idiom will continue to work too. My impression was that it could break sometime in the future.

👍 1
neumann 2026-06-04T00:00:41.490109Z

Thank you @dnolen for letting us drag you into the conversation!

➕ 2