This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-07-28
Channels
- # asami (1)
- # aws (9)
- # babashka (16)
- # beginners (32)
- # calva (2)
- # clj-kondo (20)
- # cljdoc (6)
- # clojure (35)
- # clojure-dev (25)
- # clojure-europe (11)
- # clojure-india (1)
- # clojure-norway (2)
- # clojure-spec (26)
- # clojure-uk (1)
- # clojurescript (41)
- # conjure (3)
- # css (9)
- # cursive (18)
- # data-oriented-programming (6)
- # data-science (2)
- # emacs (47)
- # events (1)
- # fulcro (15)
- # graalvm (30)
- # gratitude (7)
- # honeysql (27)
- # inf-clojure (4)
- # introduce-yourself (2)
- # lsp (129)
- # malli (7)
- # missionary (21)
- # nbb (17)
- # off-topic (18)
- # re-frame (6)
- # releases (1)
- # shadow-cljs (120)
- # vim (7)
- # xtdb (15)
Well, not traditionally. But if you're in a webworker, there's ways to claw back synchrony, such as with https://github.com/johnmn3/inmesh:
(defn post [url headers data]
(let [response-post @(future (-> got (.post url (clj->js {:headers headers :json data})) .json yield))]
(println (js->clj response-post :keywordize-keys true))))
I'm still polishing up the beta, so no formal announcements yet, but it's possible. There's caveats too, like serialization overhead, etc, but if sync control flow is what you want, it's possible. Not sure what got
is there though.And I presume you might have to wrap the .json
call in a .then
if it's a js/fetch
like thing, but yeah
Like:
(->> @(future (-> (js/fetch "")
(.then #(.json %))
(.then #(yield (js->clj % :keywordize-keys true)))))
:iss_position
(println "ISS Position:"))
;ISS Position: {:latitude 44.4403, :longitude 177.0011}
@thheller yea, I'm actually not used to it. I'm writing a lambda right now on nbb that is supposed to do some business logic depending on the state of stuff that is behind an API. It's surprisingly different from developing for the browser, where the state-propagation-rules are usually taken care of by a framework and you're always working with some implementation of redux. Maybe I need some half-assed version of that for backend-logic. @john Oh that looks interesting! But I think right now using workers of any kind would add too much complexity for too little gain. But I'll check it out as soon as I see a use case for it!
@roseneck If it helps, nbb has a REPL(!) helper called nbb.core/await
which lets you pull out the resolved value. It works only in the top level.
(def foo (nbb.core/await (async-fn)))
or in the REPL:
user> (nbb.core/await (async-fn))
Even in JS you cannot "pull out" the resolved value if you have async await: functions will always return promises once you use async/await.
@roseneck The general idea behind a "promise" is that the promise itself is a thing which you can return and then pass around, even while the underlying value may not exist yet.
(defn post [url headers data]
;; ... Wrap invocation of post request inside promise creation,
;; or invoke post with a lib that returns promise for you...
;; ... probably attach some minor transforms to result ...
;; ... return promise
)
;; The "return value" of `post` is now a promise to provide
;; some real value eventually, i.e. when the request succeeds.
(def my-post-response (post url headers data))
;; Do something with the underlying value whenever it actually exists.
(p/then my-post-response some-side-effect)
(def my-transformed-post (p/then my-post-response transform-fn))
(p/then my-transformed-post some-other-side-effect)
The conceptual model of promesa is captured by p/deferred
, p/resolve!
, and p/reject!
to create promises (p.deferred
creates an unresolved promise, which you can return to consumers, and then resolve/reject when data becomes available), and p/then
, p/catch
to consume them.
Everything else the lib offers is essentially just sugar.(/ 1 "2")
;; cljs.core//, all arguments must be numbers, got [number string] instead
(/ 1 (deref (atom "2")))
;; 0.5
Is this a bug?Seems strange that dereffing to a string doesn't raise the same error, but I don't know if that's a bug exactly.
Oh. Ok, so it's not a runtime exception it's failing static analysis. That makes me a little sad.
(defn ^number /
"If no denominators are supplied, returns 1/numerator,
else returns numerator divided by all of the denominators."
([x] (/ 1 x))
([x y] (cljs.core/divide x y)) ;; FIXME: waiting on cljs.core//
([x y & more] (reduce / (/ x y) more)))
(core/defmacro ^::ana/numeric divide
([x] `(/ 1 ~x))
([x y] (core/list 'js* "(~{} / ~{})" x y))
([x y & more] `(/ (/ ~x ~y) ~@more)))
Yea, it looks like it just expands into javascript divide.(zero? (deref (atom "0")))
;; false
(core/defmacro ^::ana/numeric zero? [x]
`(== ~x 0))
"0" == 0
true
Clojurescript is giving me javascript behavior for division such that 1 / "2"
and (/ 1 (deref (atom "2")))
give 0.5
but clojurescript isn't giving me javascript behavior for equality since "0" == 0
gives true
while (= (deref (atom "0")) 0)
gives false
.
I had code in my app that checks for zero in the denominator but it was blowing up since I was passing a string "0". That's how I found this.
(let [zero (atom "0")]
(when-not (zero? @zero)
(/ 1 @zero)))
;; ##Inf
Oh. zero?
uses ==
which is js ===
strict equality. TIL that https://clojuredocs.org/clojure.core/== exists in clojure.
Ok, and then =
only returns true if they're identical.
(defn ^boolean =
"Equality. Returns true if x equals y, false if not. Compares
numbers and collections in a type-independent manner. Clojure's immutable data
structures define -equiv (and thus =) as a value, not an identity,
comparison."
([x] true)
([x y]
(if (nil? x)
(nil? y)
(or (identical? x y)
^boolean (-equiv x y))))
([x y & more]
(if (= x y)
(if (next more)
(recur y (first more) (next more))
(= y (first more)))
false)))
(extend-type number
IEquiv
(-equiv [x o] (identical? x o)))
Thanks!Sorry if this is a really dumb or confused question but I have heard that the ClojureScript compiler is/can be made to be self-hosting, and so I was just wondering why is it not common practice to compile ClojureScript only with itself (i.e., forego use of the JVM, and compile using something like node)? I also don't understand why something like nbb is needed which runs on the SmallClojureInterpreter, if there's also just the regular ClojureScript compiler which could also compile Clojure to run on node.
My understanding is that the self-hosted compilers produce pretty inefficient code because they're a literal translation to JS -- and cljs really benefits from all the optimizations that are part of the (hosted) compiler. (but I don't do cljs at work yet, only clj, so my voice is not at all authoritative! 🙂 )
the self hosted compiler does produce the same JS that the regular compiler does. there is no or very little difference there. however the self-hosted compiler has certain restrictions that prohibit certain post-compile optimizations.
while a regular fully optimized build starts out at about 130kb (~30kb gzip) a self-hosted build starts out of several megabytes
@UEH6VEQQJ just to say that if it helps I have asked similar questions in the past so it's not more stupid than the random sample of "me"
I don't really know what I'm talking about so don't take this as gospel but I think the clojure(script) world has a larger centre of gravity towards the (clojure==java) side, there are definitely people using only cljs or cljs and arbitrary backend but my guess would be that most (cljs) is talking to (clj), so most people already have a java dependency, and their best developers are most familiar with java
so the idea of eliminating a java dependency isn't as interesting for those people as it would be to people who usde cljs-only, and there's more of the first type
So then it sounds like the only missing link is a JS optimizer that runs on Node? Maybe there is such an optimizer out there
There was a JS version of the Google Closure compiler (used by CLJS) but it looks like they discontinued it: https://github.com/google/closure-compiler-npm/blob/master/packages/google-closure-compiler-js/readme.md