Fork me on GitHub
#clojurescript
<
2021-04-26
>
zane01:04:44

When compiling a namespace that defines a function named binds a variable to eval to JavaScript I get this warning:

WARNING - "eval" cannot be redeclared in strict mode
I would have expected that either --compile-opts '{:output-wrapper true}' or --compile-opts {:rename-prefix "…"} would resolve this, but it doesn’t seem to. Is there another way, or do I have to rename the function variable?

zane02:04:15

Actually, seems like it’s a let-bound variable named eval that triggers the warning.

sova-soars-the-sora03:04:22

naturally when you overwrite an indigenous function name there will be a warning. do you want the warning to not happen?

sova-soars-the-sora03:04:38

I would recommend renaming the variable to some other word that isn't a special word, but i'm not an expert.

sova-soars-the-sora03:04:26

How can I

{:on-click (fn [e] (gc/toggle node "invisible"))}
specify the node that is being clicked upon?

sova-soars-the-sora03:04:51

(.. e -target -value) is kinda in the ballpark... not sure if that's the thing

sova-soars-the-sora03:04:38

I basically want to create a "flip" effect that hides one div and shows another (sibling) div

sova-soars-the-sora03:04:19

(. e -target) did the trick

sh5408:04:26

I notice that the clojurescript version of hash floors and floating point numbers and then just treats them as ints. This is different to the behavior in clojure which is a little annoying. https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L1012

sh5408:04:29

So #?(:cljs (is (= (hash 1.2) (hash 1.3)))) yet #?(:clj (is (not= (hash 1.2) (hash 1.3))))

sh5408:04:32

I get that hashing stuff with floating point numbers in them is probably generally not a great idea but would be nice for my particular case. I am compiling clojure forms to shaders and triggering hot reloads if they change and have been using hash on the new and comparing it to the stored hash of the old to see if things need replacement. Works great unless I try to change a float ever so slightly.

sh5408:04:42

Any recommendations on how to go about things? It would be nice to use the built in hash. It won’t take that long to write my own special hash but I would prefer to rely on core for this kind of thing.

thheller08:04:50

don't use the hash to compare stuff 😉

sh5408:04:41

hehe noted. I wouldn’t normally but its dev tooling so I can tolerate the low collision chance. Doing a full new form to old form = hurts the hot reload speed since right now my relevant def macro does the comparison and so the general shadow-cljs hot reload does not get finished until all those macros get done. It can be a little too slow if the file I edit is required in a bunch of other places.

sh5408:04:23

I could conceivably push my shader hot reload stuff to a queue and async process that after the shadow-cljs hot reload is done but I’d still like the actual compare to be reasonably performant

thheller08:04:14

don't know how you are doing stuff but if its a macro you could have that compute something based on the form that you store alongside the output

sh5409:04:06

yeah thats how it is currently done with hash as the function computes what I store alongside the output

sh5409:04:49

works great unless I want to change a 1.2 to a 1.3. Though that works fine in the clojure version of my project.

thheller09:04:20

maybe just pr-str the form and md5 it or so. no clue what you are doing exactly 🙂

sh5409:04:00

oh yeah, good idea. thats a quick alternative.

sh5409:04:05

(my-md5 (pr-str form)) is quite a bit slower that (hash form) when I just test a bit in the repl. That being said they are both pretty fast in absolute terms so i’ll just have to see how it feels in my workflow.

p-himik09:04:28

If the forms are compared within the JVM process, comparing the results of pr-str might be faster, because md5 consumes the whole string either way. But then comparing the forms themselves should be even faster, but you say that it's slower.

sh5409:04:12

I’m looking at some code I wrote a good while ago so I am just relying on some notes I wrote at the time that say that comparing the forms was slow though I will double check now.

sh5409:04:48

also I checked my macro magic and I am doing the actual compare in the browser. I am only hot reloading my shaders when I am developing so it is unnecessary to compute and store anything during compilation.

sh5409:04:49

Sorry for the lack of clarity! Trying to explain a little part of of a larger thing without bringing in too many unnecessary details.

p-himik09:04:44

> I am doing the actual compare in the browser. Can it be done in the JVM process?

p-himik09:04:53

Without sending anything, I mean.

sh5409:04:43

potentially. The macro would probably have to do the computes and store to metadata. Then the runtime bit of things would just compare old and new and call the hot reload “hook” if they are different.

sh5409:04:36

and = is like 300 times slower in my tests in both clj and cljs. I was testing under the assumption that things are most likely equal which I assume is worst case of the = function. And that the old and new form don’t “share” anything between them which I don’t know if is true or not.

sova-soars-the-sora14:04:03

Any tips on how I can make one 2 divs, one default hide, one default show, and click to switch that?

p-himik15:04:32

Do you use any UI library? If so, it's better to ask in the appropriate channel, e.g. #reagent for Reagent.

sova-soars-the-sora15:04:19

Thanks. I am using rum. I managed to figure it out! ^_^ keeping a local state and toggling between -1 and 1 via #(* -1 %)

👍 2
Aron15:04:48

I was about to suggest Element.classList.toggle 🙂

sova-soars-the-sora15:04:27

I tried to do toggle but i have 2 elements. so rather than toggle them both i have one local atom and if its value is -1 one class is conditionally set, if it's +1 the other class is conditionally set

Aron15:04:49

obviously doesn't matter in most cases, but changing class attribute on 2 elements is a lighter operation for the browser than adding/removing two elements

Aron15:04:55

wait, I got confused, you are not removing elements, but I don't quite understand, if you are generating your html, how does that work, what is the mechanism that changes the class? is it's react or something?

yuhan16:04:19

using +1 and -1 is a bit odd, why not true/false and toggle with not?

yuhan16:04:01

or even better, name the states something meaningful and toggle between them with a map: eg. (swap! state {:dark :light, :light :dark}), you can do any number of "state transitions" this way

sova-soars-the-sora17:04:58

it might be good to have multiple states... i don't understand the line (swap! state {:dark :light, :light :dark})

sova-soars-the-sora17:04:09

@U0VQ4N5EE i'm using Rum

[:div.thang {:class (if (= -1 @visibility-atom) "invisible")
     			:on-click (fn [e] (swap! visibility-atom #(* -1 %)))} 

sova-soars-the-sora17:04:58

It's like a fake "flip to see the back of this div" but really it's not the back, it's just another div, and i hide one and show one depending on the value of @visibility-atom via the if statement in the :class attribute

sova-soars-the-sora17:04:43

@UCPS050BV maybe you could elaborate on your mini state machine there

sova-soars-the-sora17:04:51

say I want to have 3 modes instead of 2

yuhan17:04:31

say you have 3 states, using keywords :a :b :c to denote them

(def *state (atom :a)) ;; initial

(def transitions {:a :b, :b :c, :c :a})
This would cycle between all 3 states
(swap! *state transitions)

sova-soars-the-sora17:04:46

well that's cool and pretty mind-blowing

yuhan17:04:18

Yup, the "maps/sets/keywords as functions" idiom is quite powerful if you get used to it 🙂

yuhan17:04:59

note that you might want to guard against invalid states by using #(get transitions % <default>), or using case which throws an error #(case % :a :b, :b :c, :c :a)

sova-soars-the-sora17:04:04

Ah that is helpful, to have a fall-back...

yuhan17:04:31

I actually use case most of the time for these things, it's better to catch errors early than have a nil cause damage down the line

sova-soars-the-sora17:04:39

sure. easier to pinpoint the leak

sova-soars-the-sora17:04:30

clojure is so awesome. that's maybe the simplest code ever for a working state machine.

sova-soars-the-sora17:04:57

the list of states is also a function for advancing states... brilliant and beautiful

2
sova-soars-the-sora18:04:04

thanks for your help everyone, i got a lot done this morning ^.^

brtmr18:04:13

Hi, I need some help with tooling. I have a web app with a ring-backend in clojure and a reagent frontend in clojurescript. I am using cursive with leiningen. I can run my frontend through figwheel and develop with code-reloading, and I can use the lein ring plugin to run the backend with code reloading. I have found bits and pieces on the figwheel home page / github wiki, but everything either assumes that I am either using deps.edn instead of leiningen is using outdated APIs.

Aron21:04:25

fwiw, before shadow-cljs and deps.edn became a thing, I was unable to adopt clojure because both lein and boot were way outside of what I could reach with respect to my time and other constraints. 7 years I knew about clojure but had no way in. I was limited to using cljs packages compiled to js.

brtmr18:04:19

Edit: What I am trying to do is run them both in tandem: Backend and Frontend, possibly with code reloading/ a REPL on either side

gorjusborg23:04:20

how do people do interop w/ js promises in cljs these days? I see promisea, and the <p! macro w/ core.async... but what's idiomatic?