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?
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.
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.
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.
I'm skeptical about the utility of a mutable proxy -
what API are you using that actually needs this?
I don't think it will ever be slower than cljs->js- mostly because we're not converting anything at all.
and yeah the laziness is a big win
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.
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.
Oh I should clarify, react form libraries*. When they're using controlled components rather than uncontrolled.
@dominicm there's a lib: cljs.bean, that might be helpful for you, it's also lazy in the transformations
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?
access via proxies is actually faster than get etc.
Proxies are the only practical way.
EXPERIMENTAL because it's new and feedback needed.
cljs->js for that access pattern sounds fine - but I would experiment and see if it's necessary
Got it, thank you
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?
mquickjs doesn't support ES6 which is now the baseline for CLJS since the last release
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?
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
};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.coreyeah, I can repro with:
try {} catch (A) {}
try {} catch (A) {}
Seems like a bug in mqjs to me? Maybe file a report?From the docs:
> β’ The variable associated with the catch keyword is a normal variable.
It probably has to do with that
You could try -O simple
I suspect GC doing this optimization
tried -O simple, but this lets me run into the documented eval limitation
why does simple use eval?
it contains multiple ones. the first mquickjs chokes on being
{var isChrome87=!1;try{isChrome87=eval(goog.global.trustedTypes.emptyScript)!==goog.global.trustedTypes.emptyScript}why is that in simple, but not in advanced? weird
maybe this is because of target none?
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:12this does work:
try { console.log((1,eval)('1+2'))} catch (A) {}
you could manually replace eval( with (1,eval)( for now maybeyeah, Iβll play around a bit more and try with work arounds like this in the next days
what do you want to use mqjs for
no particular use case (yet), I was just curios
Not against it, based on the above I suspect Closure Compiler might cause more trouble than anything we're actually generating