Fork me on GitHub
#squint
<
2022-09-03
>
borkdude08:09:08

Interesting, just learned about JS Proxy and thought, hmm, could this be a way to have immutable.js play well with interop and then found this: https://www.codementor.io/@rexogbemudia/immutable-js-wrapper-utility-o3qnatjlp

borkdude08:09:12

And now I understand the idea of immer too which also uses proxies

borkdude09:09:11

(ns immer (:require ["immer$default" :as produce]))

(def v1 {:a 1})
(def v2 (produce v1 #(assoc! % :b 2)))
(prn v1 v2 (= v1 v2))
So this produces an "immutable" v2 from v1 which works with any JS API. The script yields 11kb minified/bundled with esbuild which is the best one I've seen so far. Caveat: it still doesn't implement "value equals", but it assumes a unidirectional mutation such that the newest one is always equal to itself, which is I think reasonable in a lot of use cases

borkdude09:09:12

And this will crash: (def v3 (assoc! v2 :foo :bar)) - which is pretty neat...

borkdude09:09:28

^ @mkvlr Thanks for sharing that

🙌 1
borkdude09:09:45

It works in the playground too:

mkvlr10:09:23

are you still using strings for keywords? Wondering if there's a way to preserve more of Clojure semantics with this approach.

borkdude10:09:47

in clavascript, keywords are strings

mkvlr10:09:08

and that's set in stone?

borkdude10:09:21

it's the only way to get seamless JS interop

mkvlr10:09:56

why not let folks choose? A map in clojure can also contain string keys

borkdude10:09:30

What would be the motivation to change this behavior?

borkdude10:09:48

In clavascript, {:a 1} is the same as #js {:a 1}

mkvlr10:09:49

preserving the semantics of clojure

mkvlr10:09:18

or more of it at least

borkdude10:09:39

describe use cases of a reified keyword thing

mkvlr10:09:46

for example a http handler request / context map where I use string keys for the original unmodified request params and keywords for the coerced values

borkdude10:09:18

you cannot use arbitrary objects as keys in JS objects

mkvlr10:09:12

so using objects for maps is set in stone?

mkvlr10:09:39

I guess clavascript just isn't for me then and I'll keep rooting for #cherry then 🙃

👍 1
borkdude10:09:47

I think making different choices just makes you work against JS which is not the idea of clavascript

mkvlr10:09:03

last q: two different maps are not an option?

borkdude10:09:53

there is an idea to have #map {:a 1} which defers to js/Map so you can have arbitrary keys. assoc etc already work with js/Map

mkvlr10:09:08

a default one with clojure semantics and letting folks opt into an interop map that's backed by js map?

mkvlr10:09:55

it works only accepting strings and keywords as keys, which I think means a lot of existing clojure code will break

borkdude10:09:33

clavascript is not a drop-in replacement for existing clojure code

mkvlr10:09:04

but maybe supporting that is not your motivation here

borkdude10:09:12

although porting @U34K4458X’s hn-reader from cherry to clava only took minimal effort

borkdude11:09:18

clavascript isn't intended as a CLJS replacement: it's intended for the new/niche use case of wanting to write JS with small bundle sizes, but with a saner UX: structural editing, some drop-in stdlib functions which are similar, etc

borkdude11:09:12

E.g. I could write a script in Clava and upload it to my watch which only has a few kilobytes of ram/storage

borkdude11:09:26

Another use case is e.g. writing Github Actions, Chrome extensions, etc. Which are usually full of interop and it's nice to have those as small as possible since sometimes load on every page load. Can't afford much there

borkdude11:09:01

This is why we have both cherry and clava. So people have a choice ;)

👍 2
borkdude11:09:13

I've found several bugs in clava which I can port back to cherry. The problems are similar in clava and cherry so I don't see why we can't have both.

borkdude11:09:20

This is why I forked clava from cherry

Lyn Headley14:09:58

Is there any way to emit a[0]? Or should I stick with (get a 0)?

Lyn Headley14:09:38

Is there anyway to emit: import './popup.css';

borkdude14:09:01

@laheadle You can (aget a 0)

borkdude14:09:15

yes, (ns foo (:require ["./popup.css"]))

Lyn Headley14:09:46

Unfortunately this does not emit the import:

Lyn Headley14:09:57

(ns local-chrome-extension.popup (:require ["./popup.css"])) (a)

borkdude14:09:39

hmmm, let me look into that

borkdude14:09:33

I see what's going on

borkdude14:09:58

let me fix this, just a minute

borkdude14:09:46

meanwhile, a workaround:

(js* "import './popup.css'")

borkdude14:09:30

Should be fixed now with the version just pushed to npm

Lyn Headley15:09:43

awesome, thank you!

Lyn Headley15:09:35

Is this idiomatic?

(set! (.. (js/document.getElementById :counter) -innerHTML) initialValue)

Trying to translate: document.getElementById('counter').innerHTML = initialValue;

Note that per the website, my code actually emits:

document.getElementById("counter")["innerHTML"] = initialValue;

borkdude15:09:50

does it work? :)

borkdude15:09:59

you could also do:

(set! (.-innerHTML (js/document.getElementById "counter")) initialValue)
but it it works, it works

✔️ 1
Lyn Headley22:09:51

looks like letfn is not implemented, is that right?

borkdude06:09:00

Correct, issue welcome