This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-01-28
Channels
- # babashka (28)
- # beginners (252)
- # bristol-clojurians (2)
- # calva (28)
- # cider (11)
- # clj-kondo (15)
- # cljs-dev (7)
- # clojure (378)
- # clojure-europe (4)
- # clojure-italy (4)
- # clojure-nl (3)
- # clojure-norway (4)
- # clojure-uk (32)
- # clojurescript (128)
- # cursive (39)
- # data-science (18)
- # docker (37)
- # figwheel-main (10)
- # fulcro (45)
- # ghostwheel (7)
- # graalvm (2)
- # hugsql (1)
- # jobs (2)
- # joker (5)
- # kaocha (5)
- # luminus (12)
- # off-topic (37)
- # onyx (4)
- # pathom (22)
- # pedestal (70)
- # re-frame (7)
- # reagent (30)
- # ring (4)
- # shadow-cljs (12)
- # spacemacs (1)
- # sql (26)
- # tools-deps (7)
- # vrac (2)
- # vscode (7)
- # xtdb (27)
okay may be a silly question i am using secretary
for routing and want to know what the if a particular link is active or not is there a straightforward way to do it?
@varen90 You can store the current route in some atom or if you're using re-frame, the re-frame db
@feikas If *ns*
doesn't work, you can maybe try to use the metadata on vars: (ns foo) (def x) (:ns (meta (var x)))
, although I'm not sure if that works with (advanced) compiled code...
tried this:
clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.597"}}}' -m cljs.main -t node -O advanced -c foo.core
with foo.core being the code abovethere is no such thing as a "current ns" in a function. that only exists at compile time/macros. do not go with var
, that adds way too much "noise" into your code.
resolve is a macro because the analyzer data is not available at runtime like in clojure, thus you can't access it dynamically
hmm, this seems to work:
(ns foo.core
#?(:cljs (:require-macros [foo.core :refer [curr-ns]])))
(defmacro curr-ns []
`'~(ns-name *ns*))
(defn foo []
(prn (curr-ns)))
(foo) ;; prints foo.core
yes, thats a macro. thats works fine because at compile time *ns*
is bound to whatever namespace is being compiled
looks like it! while we’re talking about this, there’s no way to dynamically resolve a var at runtime in cljs?
https://github.com/clj-pour/pour/blob/master/test/pour/core_test.clj#L140-L143 that’s the CLJ behaviour
in this case, that’s probably fixable as your suggestion previously, as it’s not dynamic as such
so, making it a macro would let it resolve that stuff at compile time. would be nice to make it be able to take different kind of queries at runtime though
Is it in any way possible to use require inside a defn? For example:
(defn do-something []
(require 'some.cljs.namespace)
(do-something-else))
Why I would want this: There's a piece of code in the Integrant library that's Clojure specific. Because it uses a require within a defn https://github.com/weavejester/integrant/blob/ca8d6327708cf291f2f310d476124271fcbe0b89/src/integrant/core.cljc#L186-L200 I was wondering if it was possible to make this possible for ClojureScript.
@kevin.van.rooijen no, not possible
Hello! Does anyone know the way of returning JS literal like #js {:a 1 :b 2}
from a macro? I'm getting *No reader function for tag js*
exception
@andrewboltachev you can use ~(cljs.tagged-literals/read-js {:a 1 :b 2})
or construct JSValue
directly if you want to skip the validation
@thheller ah, the JSValue
. I somehow thought it's only for parsing, so thanks!
writing a macro and I would like to have a helper function which would tell me that given value can be emitted as primitive cljs type as-is wondering if something like this already exists somewhere…
don't think there is a function for this but you are missing nil?
, boolean?
and symbol?
Hey 🙂! Is anyone trying to work with shadow-cljs
, react-native-web
and ui-kitten
without expo
?
I have a macro which is processing a map, I’m generating cljs code based on visited keys and values. My issue is that I need to generate the code in the same order as individual keys/vals appeared in the source code. Naively iterating over a map value in macro seem to not preserve the order. Any ideas?
maps are not ordered
so this isn't going to work with a map as is
if you look at something like let
, the use of a vector for bindings enforces a semantic order
thanks for the suggestion, this is part of an effort to translate react props passed as cljs map to js conventions (at compile time), not sure if this a-vector-instead-of-a-map proposal would be palatable in this case
the map can contain cljs symbols and forms which may be re-emitted (and wrapped) in dynamic cases but this code reodering could change meaning of the code, especially side-effecting code I think
I have to emit original code in the strict order as it appeared in the map - top-down btw. this is issue in the current helix implementation as well
yeah. props tend to not contain a lot of side effects, I haven’t run into that corner yet but that could be horrible to debug
we could parse the raw source code behind map form but that sounds like a very heavyweight and error prone solution
tbh I’m a little bit surprised that iterating over it in CLJ doesn’t preserve the order
I thought smallish maps used an ArrayMap that had an implicit order, though woe betide those who might rely on that and then add one more key…
I discovered it by accident, writing some tests and then wondering that my generated code is not stable
that probably is the key, it is a reader tag which translates the map into (JSValue. …), I believe there is no map involved, and args order is used to gen underlying js object
Another potential reason to care about the order is the fact that iterating over JS object keys/entries is done in a specific order. Although, it's a bit more complicated than just preserving order. But I'm not sure if non-string keys are applicable in React, so maybe it is just the insertion order. An issue with parsing a map literal manually is that now you have to have a map literal - you cannot use any binding in its place.
:thinking_face: I thought the reader tags would still read the { … }
literal into a map, just at read-time
also I’m looking at JSValue just now and it seems to accept just one object as arg (which would be the map value I guess)
@U2FRKM4TW I think our issue right now is codegeneration, we translate a piece of cljs into another piece of cljs code, but we don’t necessary preserve order of original map keys/vals - it is not related to runtime behaviour of created js objects
AFAICT JSValue gets emitted using this: https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/compiler.cljc#L578
https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/compiler.cljc#L429
I guess, nobody hit this issue because most js obj literals are small direct values without calling into side-effecting functions which would depend on each other
and if they did they were probably not experienced enough to describe the issue and report it back
I can imagine having small-ish js obj literal with sideeffecting stuff and then adding one extra key would flip it from array-map to persistent map and my side effects get reordered
this is not a good proof, you would have to look at generated code, here you rely on runtime js iteration/presentation of js vals
I think the issue has nothing to do with React, props, etc. The issue is that you should not rely on the order of values in map literals. A similar topic has been discussed before - map destructuring where latter keys depend on the former. In general, it doesn't work. The solution, at least in that case, is to just compute everything that is order-sensitive before constructing the map. And then construct the map with the resulting values, already computed.
emit-js-object
is the function that spews out the JS object. And it does iterate over a map created earlier via #js {...}
. The order is not guaranteed.
well, since the same issue is (probaly) in cljs itself, it could be our excuse to simply not care and leave it as undefined behaviour but I don’t like it, someone has working cljs code, wraps it in my macro and now suddenly it works incorrectly
@darwin Just to make sure I understand correctly - it's your macro and not the user code that introduces the dependency on the order, right? I.e. the user might not care about the order at all.
@U2FRKM4TW the issue is that a user might write something like:
(props {:foo (i-do-side-effects)
:baz (i-do-side-effects-too)})
and when that map gets > a certain size, it might re-order those side effects@U4YGF4NGM It would be the error of the user.
In that case it must be something like
(let [foo (...), baz (...)]
(props {:foo foo, :baz baz}))
it’s surprising because if it was, in fact, a CLJS map the order of instantiation would be preserved
@U4YGF4NGM How do you tell users to not make language mistakes in general? :) The limitations of the platform that affect everyone, including your library users, in general are not your library's concern.
@darwin But is it the user code that's order-dependent or the code within your macro? If the former, you don't need to do anything - otherwise, you would be just applying a band-aid on something inherently broken by the user. And there are many ways to break stuff, not just relying on map order.
@U2FRKM4TW I think the thing that is frustrating for darwin and I is that:
{:foo (i-do-side-effects)
:baz (i-do-side-effects-too)}
is order-preservingThe <= 8
thing is implementation detail. It will continue to work but you must not rely on it.
it just sucks, that I touch some small part of my map in tests and it generates reordered code
And the order of the execution will not be the same as the order of the computation of the items within the map literal!
I.e. in {:a (a), :b (b), ...many more items...}
, (b)
could easily end up being computed before (a)
anyway.
ok, thanks for the explanation, I have to think about this to accept this cruel fact of life have been living (and writing my code) under different assumptions 🙂
And it may continue to work for all eternity even for maps with thousands of items. But if the hash function is changed one day...
btw. this is the macro for anyone curious: https://github.com/darwin/helix/commit/62e13ab4e68073990db05e3a7ee38caadf1774e6#diff-a6dcc0ad715d8b3ed2ddd1451bcdecabR154
This just got linked to in #clojure: https://github.com/plumatic/plumbing#graph-the-functional-swiss-army-knife
Seems like it could be helpful if you really want to avoid extracting every order-dependent thing into let
.
looks like fnk
is a macro and they can probably depend on macro expander behaviour to record order of fnk
macros invocations - I have nothing like that, cannot force user to wrap his value in a macro call
but I can probably live with that explanation you gave, it is simply something people must not depend on and I will work around my test issues by optionally converting incoming maps to sorted maps just for tests
Seems like you're comparing JSON strings. But props can be functions - how would it work then? Or for any other type that's not JSON-friendly. I would probably just do a deep JS object comparison.
Actually, I retract my statement about deep comparison - you just need to compare each key-value pair and only delve deeper for the :style
key.
Everything else must be =
since you don't process the value in any way. It should end up as the very same object.
deep comparison won’t hurt, style can be recursive (at least the code is currently written to work like that)
> It should end up as the very same object. I’m not sure, did you consider dynamic cases as well?
OK, I can see that.
But you still probably don't need a library for that since the only thing you would consider a parent is a plain JS object. There's a special case of NaN
not being equal to itself but I'm not sure if there's anything else out there like that.
> did you consider dynamic cases as well?
What do you mean?
Yeah, take my words with quite a few grains of salt as well - having e fever and sleeping 4 hours in the last 48 doesn't help. :)
Please forgive me if I am beating a dead horse here, but here is a cljs Node-based REPL session demonstrating that the evaluation is not guaranteed to be source code order:
ClojureScript 1.10.597
cljs.user=> (def my-atom (atom 0))
#'cljs.user/my-atom
cljs.user=> {:a (swap! my-atom inc) :b "b" :c "c" :d "d" :e "e" :f "f" :g "g" :h "h" :i (swap! my-atom inc)}
{:e "e", :g "g", :c "c", :h "h", :"b", :d "d", :f "f", :i 1, :a 2}
keys in #js
literal do not preserve order when > 8 keys are present