cljs-dev

dominicm 2025-12-27T08:48:29.275939Z

Has any thought been given to a mutable proxy? Perhaps atom backed? JavaScript code loves to mutate an object/array and it would be helpful to pull the clojurescript map back out afterwards. Also, is there any expectation that clj->js would be slower in the case of knowing that all attributes in the data you pass will be used? Or is proxy effectively a lazy clj->js and that's where efficiencies come in?

dazld 2026-03-31T12:23:49.802669Z

proxies used to be quite slow in V8 (2015-2017), but think these days, as dnolen mentions, they’re negligible overhead unless doing really tight loop stuff.

dnolen 2025-12-29T13:03:54.140099Z

Can you show me one that works by mutating? Like whatever it is that you're using. I'm surprised that such a pattern would be common in React at all.

dominicm 2025-12-29T22:25:53.712209Z

You're right, I've misunderstood what's happening under the hood. They're maintaining their own state separately. I was hoping I could optimise a little manipulation at the business level without an inefficient back and forth.

πŸ‘πŸ½ 1
dnolen 2025-12-28T13:51:03.886689Z

I'm skeptical about the utility of a mutable proxy -

dnolen 2025-12-28T13:51:15.930919Z

what API are you using that actually needs this?

dnolen 2025-12-28T13:52:29.809689Z

I don't think it will ever be slower than cljs->js- mostly because we're not converting anything at all.

dnolen 2025-12-28T13:52:47.463279Z

and yeah the laziness is a big win

dominicm 2025-12-28T22:08:28.426599Z

Forms are the API I'm using that needs this. They want to update the form data as user types, and read it back out. There's times where I need to modify that data in response to events (eg country changes so I reset the state to nil or something) I'm working on a fairly complex form so the business logic is rather large.

dnolen 2025-12-29T00:04:30.318759Z

Do you have a link showing how this is done with JavaScript? I don't recall a way to pass an object that will be mutated. Sorry been a while since I did anything directly with forms.

dominicm 2025-12-29T06:15:13.176949Z

Oh I should clarify, react form libraries*. When they're using controlled components rather than uncontrolled.

2026-03-22T14:57:39.793129Z

@dominicm there's a lib: cljs.bean, that might be helpful for you, it's also lazy in the transformations

2026-03-22T15:20:35.589129Z

Hi, I'm not sure if this is the right channel to open this discussion. I've been thinking about the performance benefits of using cljs.proxy, and I wonder if there's perf. comparisons against clj->js anyone has made. Also, why is it marked as EXPERIMENTAL in the docstring? I have a reagent custom compiler optimized for React Native, so I was considering integrating cljs.proxy into it, did a quick Google Search on JS Proxy and found something interesting: Avoid using proxies inside performance-critical, high-frequency loops. Which makes sense to me because extractions are no longer direct, proxies add an overhead. Of course, it dependes on the operations made, probably in a highly accessed object it's better to just build the js-obj once with clj->js; wdyt? I was also thinking if an extend-type (optional, not by default) on hash-maps and vectors is possible to make them set-able and get-able from JS. Have you considered any other alternative?

dnolen 2026-03-22T15:27:03.832649Z

access via proxies is actually faster than get etc.

πŸ‘€ 1
dnolen 2026-03-22T15:27:55.145689Z

Proxies are the only practical way.

dnolen 2026-03-22T15:28:17.523649Z

EXPERIMENTAL because it's new and feedback needed.

πŸ‘ 1
dnolen 2026-03-22T15:31:04.496859Z

cljs->js for that access pattern sounds fine - but I would experiment and see if it's necessary

2026-03-22T15:39:42.338899Z

Got it, thank you

kommen 2025-12-27T21:44:12.479409Z

anybody thinks getting cljs apps running on https://github.com/bellard/mquickjs is feasible given the https://github.com/bellard/mquickjs#stricter-mode? I tried a bit and run into issues rather quick, like SyntaxError: catch variable already exists exceptions. would you be interested in repros for such issues?

borkdude 2025-12-27T22:09:05.681979Z

mquickjs doesn't support ES6 which is now the baseline for CLJS since the last release

borkdude 2025-12-27T22:11:26.450289Z

Having said that, the latest CLJS only uses ES6 features in a couple of isolated places. What is the cause of catch variable already exists?

kommen 2025-12-27T22:31:54.542429Z

looks like that the optimized code contains constructs like this, note the catch (A) is used twice

Lw.j = function() {
    h.i ? h.i() : h.call(null);
    try {
        var a = new t(null, new y(null, 4, 5, B, [1, 2, 3, 4], null), new t(null, Td.h(u(2, 3, 4), 1), null, 1, null), 2, null),
            c = hf(p, a);
        if (e(c)) {
            var d = C([H, J, w, K, M, O, S, W, Y], [null, null, Kf, null, null, u(I, new y(null, 4, 5, B, [1, 2, 3, 4], null), u(cp, u(V, u(2, 3, 4)), 1)), null, r(I, a), null]);
            Z.g ? Z.g(d) : Z.call(null, d)
        } else {
            var f = C([H, J, w, K, M, O, S, W, Y], [null, null, If, null, null, u(I, new y(null, 4, 5, B, [1, 2, 3, 4], null), u(cp, u(V, u(2, 3, 4)), 1)), null, new t(null, dp, new t(null, r(I, a), null, 1, null), 2, null), null]);
            Z.g ?
                Z.g(f) : Z.call(null, f)
        }
    } catch (A) {
        a = A, a = C([H, J, w, K, M, O, S, W, Y], [null, null, Jf, null, null, u(I, new y(null, 4, 5, B, [1, 2, 3, 4], null), u(cp, u(V, u(2, 3, 4)), 1)), null, a, null]), Z.g ? Z.g(a) : Z.call(null, a)
    }
    try {
        var g = new t(null, new y(null, 4, 5, B, [1, 2, 3, 4], null), new t(null, Td.m(u(3, 4), 2, gd([1])), null, 1, null), 2, null),
            k = hf(p, g);
        if (e(k)) {
            var m = C([H, J, w, K, M, O, S, W, Y], [null, null, Kf, null, null, u(I, new y(null, 4, 5, B, [1, 2, 3, 4], null), u(cp, u(V, u(3, 4)), 2, 1)), null, r(I, g), null]);
            Z.g ? Z.g(m) : Z.call(null, m)
        } else {
            var z = C([H, J, w, K, M, O, S, W, Y],
                [null, null, If, null, null, u(I, new y(null, 4, 5, B, [1, 2, 3, 4], null), u(cp, u(V, u(3, 4)), 2, 1)), null, new t(null, dp, new t(null, r(I, g), null, 1, null), 2, null), null]);
            Z.g ? Z.g(z) : Z.call(null, z)
        }
    } catch (A) {
        g = A, g = C([H, J, w, K, M, O, S, W, Y], [null, null, Jf, null, null, u(I, new y(null, 4, 5, B, [1, 2, 3, 4], null), u(cp, u(V, u(3, 4)), 2, 1)), null, g, null]), Z.g ? Z.g(g) : Z.call(null, g)
    }
    h.i ? h.i() : h.call(null);
    return null
};

kommen 2025-12-27T22:32:08.006189Z

compiled with

java -cp ../lib/cljs.jar:src clojure.main -m cljs.main \
    -t none \
    -O advanced \
    -co '{:language-out :ecmascript5}' \
    -o out/test.js \
    -c test.core

borkdude 2025-12-27T22:33:48.889969Z

yeah, I can repro with:

try {} catch (A) {}
try {} catch (A) {}
Seems like a bug in mqjs to me? Maybe file a report?

kommen 2025-12-27T22:39:41.465069Z

done https://github.com/bellard/mquickjs/issues/40

borkdude 2025-12-27T22:43:06.800219Z

From the docs: > β€’ The variable associated with the catch keyword is a normal variable. It probably has to do with that

borkdude 2025-12-27T22:43:48.272599Z

You could try -O simple

borkdude 2025-12-27T22:44:26.780089Z

I suspect GC doing this optimization

kommen 2025-12-27T22:45:10.920459Z

tried -O simple, but this lets me run into the documented eval limitation

borkdude 2025-12-27T22:45:29.218229Z

why does simple use eval?

kommen 2025-12-27T22:52:10.159859Z

it contains multiple ones. the first mquickjs chokes on being

{var isChrome87=!1;try{isChrome87=eval(goog.global.trustedTypes.emptyScript)!==goog.global.trustedTypes.emptyScript}

borkdude 2025-12-27T22:53:48.367249Z

why is that in simple, but not in advanced? weird

borkdude 2025-12-27T22:55:22.244539Z

maybe this is because of target none?

borkdude 2025-12-27T22:57:44.842409Z

it seems this crashes:

try { eval('1+2')} catch (A) {}
while I think mqjs should catch the exception
$ /tmp/mquickjs/mqjs /tmp/foo.js
SyntaxError: direct eval is not supported. Use (1,eval) instead for indirect
    at /tmp/foo.js:1:12

borkdude 2025-12-27T22:59:06.070639Z

this does work:

try { console.log((1,eval)('1+2'))} catch (A) {}
you could manually replace eval( with (1,eval)( for now maybe

kommen 2025-12-27T23:00:59.281789Z

yeah, I’ll play around a bit more and try with work arounds like this in the next days

borkdude 2025-12-27T23:01:48.453329Z

what do you want to use mqjs for

kommen 2025-12-27T23:05:42.872169Z

no particular use case (yet), I was just curios

πŸ‘ 1
dnolen 2025-12-28T13:49:51.422609Z

Not against it, based on the above I suspect Closure Compiler might cause more trouble than anything we're actually generating