This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-06
Channels
- # announcements (69)
- # aws-lambda (3)
- # babashka (45)
- # beginners (28)
- # calva (4)
- # clara (7)
- # clojure (23)
- # clojure-spec (5)
- # clojure-uk (18)
- # clojurescript (57)
- # clojutre (1)
- # cursive (20)
- # datomic (31)
- # emacs (5)
- # figwheel-main (3)
- # fulcro (16)
- # graalvm (7)
- # luminus (4)
- # nrepl (9)
- # off-topic (50)
- # re-frame (8)
- # reitit (2)
- # rewrite-clj (10)
- # shadow-cljs (88)
- # spacemacs (1)
- # sql (6)
- # vim (2)
why would adding datomic client library to project dependencies cause figwheel to freakout with java.lang.NoSuchMethodError: 'void com.google.common.base.Preconditions.checkState...
?
Hi all - I’m coming back to hands-on ClojureScript development after some time away, and find that things have got … complicated in my absence (Leiningen vs CLI tools, Figwheel vs shadow-cljs, lein-figwheel vs Figwheel Main, …) I’m specifically just starting out on a project to build a desktop app on top of Electron. Does anyone have advice on which would be the best starting point (or any pitfalls to avoid)?
@paulbutcher i'm not sure what the situation for electron is, there might be application templates to get you up and running quickly. In general though you can think of it like this - use lein and lein figwheel. The traditionalist approach. This still just works and is very batteries included, well documented etc. - clojure cli+fw main. This is the composable approach. There's a lot less magic and stuff hidden from view. You can see the wiring so to say. This is what I would do nowadays. The trend is for simpler more focused tools that you can combine yourself. - shadow-cljs. The big selling point as far as I understand it is that it makes consuming npm libs trivial. People who use generally love it. The downside is that it's kind of its own world. People who don't use it will find it hard to help you troubleshoot HTH!
Thanks @plexus - that matches my impression to date. I’ve had a hunt for Electron templates and there are a few, but they all seem somewhat out of date. I’d definitely welcome pointers to anything more recent if I’ve missed anything.
@thheller FWIW, my impression of shadow-cljs was that it was probably great for someone who already understands the Node ecosystem, but for someone like me who has never used it, the documentation seemed to be assuming a lot of tacit knowledge I just don’t have (and don’t particularly want to acquire unless there’s a good reason).
@paulbutcher you don't really need to know much besides how to install node and how to use npm install react
. if you are building an electron app your are going to need to get familiar with it regardless
@thheller what I mean by that is that it lives outside of lein/clojure cli/boot. e.g. when using shadow-cljs you put your dependencies in shadow-cljs.edn instead of deps.edn for example.
yes and no. you can use deps.edn or project.clj if you like. you don't even have to use the shadow-cljs
command itself if you don't want. you can run clj -m shadow.cljs.devtools.cli watch app
(or via an alias, same as figwheel-main)
see https://code.thheller.com/blog/shadow-cljs/2017/11/18/the-many-ways-to-use-shadow-cljs.html
just trying to understand why you'd describe this as a downside. just curious. I can understand people that prefer to build their own tooling instead of using something pre-made
this is not a criticism, it's just a difference in taste and design choices. I like to see the wiring, because sooner or later I need to troubleshoot something and I can't do that if I don't know how things fit together. I know I can find out how things fit together, but some tools make me work harder to do that and that is generally not to my taste.
So I’m working through the instructions at https://rigsomelight.com/figwheel-main-template/ and I suspect I’m missing something really simple. I can run my project and see the live tests in the browser (all good). But when I try to run the tests from the command line with “clj -A:fig:test”, I get:
Error in command line args
-- Spec failed --------------------
["-co" "test.cljs.edn" "-m" "hello-world.test-runner/hello-world.test-runner"]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
should be a CLJS namespace available on the classpath
__ Doc for -m --main _____
Call the -main function from a namespace with args
-------------------------
Detected 1 error
I suspect I’m missing something really basic - any pointers?I’m not sure where the /
is coming from - the relevant line in deps.edn
looks like this:
:test {:main-opts ["-m" "figwheel.main" "-co" "test.cljs.edn" "-m" opentrack.test-runner]}
(this is a completely un-edited project generated by the Figwheel main template)
(I’ve not changed anything at all)
(I’m going to ask this question in the figwheel-main channel)
@paulbutcher :main-opts
should be only strings. no symbol. ["-m" "figwheel.main" "-co" "test.cljs.edn" "-m" "opentrack.test-runner"]
Ah! That seems to have fixed it, thanks. Looks like a bug in the Figwheel main template - I’ll put together a pull request to fix it.
Thanks!
Can you share your experience about server side rendering for cljs? Especially for re-frame.
Can someone help me understand how ClojureScript checks collection equality? I thought it was supposed to be consistent with the "hash" function, but that behaves strangely with decimal numbers, it's just truncating them:
cljs.user=> (= [1.2] [1.9])
false
cljs.user=> (= (hash [1.2]) (hash [1.9]))
true
cljs.user=> (hash 1.2)
1
cljs.user=> (hash 1.9)
1
It is probably best to consider the hash
function an implementation detail and never access it manually
I see, a working hash function would be useful for me though, do you know some alternative?
I need to "snapshot" a nested collection into a scalar value, so I can cheaply compare these hashes without having the original collections
Yes, it's super weird. The docs for "hash" say it's consistent with =, but look at this:
cljs.user=> (= (hash nil) (hash 0.2) (hash 0.9))
true
Any hash function with a 32-bit result, as Clojure/JVM does (I suspect ClojureScript does, too?) must have different input values that return the same hash value.
When someone says "hash is consistent with =", they mean "if (= x y) is true, then (= (hash x) (hash y)) is also true"
It does not mean that if (= (hash x) (hash y)) is true, then (= x y) is also true.
So if hash is consistent with =, and you find out that (hash x) and (hash y) are different, you can quickly conclude that (= x y) is false, but you cannot conclude anything from (hash x) and (hash y) being the same.
I see, so I guess the equality operator (=) does some further checks when the hashes are equal
I don't know the implementation of = in ClojureScript in detail, but it might not even use the hashes at all.
I know that in Clojure/JVM, = does not refer to the hash values at all.
The docs say equality checks are supposed to be cheap even for deep collections, I thought it must be using the hashes
The most common optimization there is to quickly check if two objects are the same object in memory. If they are, quickly return true without doing deep =, because deep = must be true.
With the implementation of Clojure's persistent data structures, suppose you have a map m1
with many keys and values. Then you create a map m2
that is the return value of (assoc m1 :x 5)
. If you do (= m1 m2)
, they are not identical, but large subtrees of their internal data structures will be.
So the deep = will start happening, but at various intermediate points will quickly return true when it finds subtrees that are identical objects in memory, which many of them will be.
If you create two maps m1
and m2
that are deep = "from scratch", with no common history, then deep = must go all the way down.
but it is common that deep trees being compared to each other share lots of sub-structures.
All of that said, the ClojureScript developers might consider it a performance bug that (hash 1.2) is equal to (hash 1.9), since that probably means there are way too many pairs of floating-point values that also have identical hash functions?
That would cause performance problems if one created large maps and/or sets with those values as keys.
For comparison, here is output from Clojure/JVM with version 1.10.1:
$ clj
Clojure 1.10.1
user=> (hash 1.2)
213909504
user=> (hash 1.9)
1503133696
It seems all "hash" does for JS numbers is (js-mod (Math/floor x) 2147483647)
https://cljs.github.io/api/cljs.core/hash
Given that lots of floating-point arithmetic gives approximate results, perhaps people do not often use approximate values as map keys or set elements terribly often -- it seems like trying to write an application like that would often lead to mismatches due to the approximations done in arithmetic.
Interestingly hash
on a number used to be the identity function. Changed with https://clojure.atlassian.net/browse/CLJS-435