This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-01-27
Channels
- # announcements (1)
- # aws (10)
- # babashka (53)
- # calva (133)
- # clj-kondo (46)
- # cljdoc (6)
- # cljs-dev (33)
- # clojure (105)
- # clojure-boston (1)
- # clojure-europe (11)
- # clojure-nl (4)
- # clojure-poland (1)
- # clojure-switzerland (6)
- # clojure-uk (13)
- # clojurescript (106)
- # cursive (1)
- # datascript (2)
- # emacs (13)
- # events (1)
- # figwheel-main (4)
- # fulcro (17)
- # graphql (8)
- # heroku (2)
- # honeysql (8)
- # lsp (76)
- # luminus (30)
- # malli (12)
- # meander (23)
- # music (1)
- # nextjournal (83)
- # off-topic (6)
- # pathom (3)
- # polylith (19)
- # re-frame (8)
- # reagent (2)
- # reveal (3)
- # shadow-cljs (54)
- # sql (9)
- # testing (11)
- # tools-deps (15)
- # xtdb (14)
on the clojure.math
naming issue? Should we not start with cljs.math
from the outset? We have automatic aliasing for clojure.* -> cljs.*
so clojure.math
will still work? When using clojure/math.cljs
we eternally have a namespace that cannot ever have macros since clojure/math.clj
already exists. It doesn't have macros yet but there might be a point where we want to? even if we just use the macros to do some inlining?
I could see the benefit in changing the simple wrapping functions, e.g.
(defn pow
[a b]
(js* "Math.pow((~{}), (~{}))" a b))
I note that this doesn’t need a macro, though from what I can see, functions that use js*
are typically defined in the cljs.*
namespaces instead of the clojure.*
ones.
I’m OK with this change, but I’d like to defer to people like David who have a better sense of where things should go.Why does clojure.math
prevent using macros? You could place the macros elsewhere and load them from there?
ah that's true about inlining macros - @quoll what @thheller is talking about is avoiding a classpath clash - I think that is reasonable
@borkdude the problem is you need the runtime file and the macros file to have the same name for the ClojureScript compiler to automatically load the macros for consumers of the library
then for clojure.string
shouldn't that also have happened? There might be similar optimizations to be made there using macros
yeah, the same applies there but it predates the pattern of using the self-requiring :require-macros
pattern to make macro use "prettier"
Sorry, when I talked about the js*
form I was thinking about this as the inlining mechanism in macros, and that it would have to be in another file.
From what I see here (and seeing how namespaces like core
work), then what I think is consistent is to have inlining macros in, say, src/main/clojure/cljs/math.cljc
, and that these can be loaded with the existing clojure.math
? Is that right? If so, then is it OK that the function-based file stays where it is?
js*
is not for inlining. (math/pow 1 2)
will still end up as a call to (cljs.math/pow 1 2)
. you could change the impl to (defn pow [a b] (js/Math.pow a b))
and it would be identical to the js*
. the inlining is done by having a macro of the same name that just changes the output to bypass the call to cljs.math/pow
@quoll You're probably aware of this, but if not: CLJS has the concept of macro-fns
: a call to a function can go through a macro first, if it's called in function position, while in non-function position it would always fall back on the function implementation.
More info here: https://blog.fikesfarm.com/posts/2015-12-12-clojurescript-macro-functions.html
That allows you to do optimizations, while always being able to refer to the function value as a normal function as well.
OK, I have my head on with fewer distractions now. Forgetting what I was saying earlier… would it be useful to create a macro like:
(defmacro pow [a b] (list 'Math/pow a b))
?
Right now, if something uses (clojure.math/pow a b)
in a function it gets converted into:
cljs.math.pow.call(null,a,b)
which isn’t idealthats only true for non-optimized builds. :advanced
builds will have :static-fns true
. that'll eliminate the .call
. :advanced
will also very likely take care of cljs.math.pow
and just end up replacing it with the inlined Math.pow
directly
it’s hard to predict what it can eliminate though; if I see it can’t produce good enough code i’ll make a macro to emit code it could do a better job with
IOW a pow
macro like you suggest will probably more predictably and consistently produce faster js, but may not actually be necessary to do so, and you lose the ability to redef that var reliably in e.g. a repl (non-advanced compilation) context.
@fogus hrm am I misreading this line? https://github.com/clojure/clojure/commit/3c9307e27479d450e3f1cdf7903458b83ebf52d7#diff-1a4951b5bd2aaff1be2a8bcaaa6cbfa4617ba50584f1d989cb0af88412cdb20dR94
in the first iteration of the loop i=0, j=0 so equalKey
is true - then you take the slow path
yes, it's checking for duplicate key, per the docstring
while j<i
though? /cc @fogus
what @alexmiller said
@fogus @alexmiller thanks! getting close
this one is pretty subtle too IMO
good as a review for clj side too!!