This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-02-09
Channels
- # announcements (3)
- # babashka (17)
- # beginners (75)
- # calva (43)
- # cider (1)
- # clj-kondo (54)
- # cljdoc (8)
- # cljs-dev (70)
- # clojure (83)
- # clojure-europe (27)
- # clojure-nl (4)
- # clojure-norway (4)
- # clojure-spec (8)
- # clojure-uk (13)
- # clojured (2)
- # clojurescript (47)
- # community-development (4)
- # conjure (2)
- # cursive (3)
- # datomic (5)
- # emacs (5)
- # events (3)
- # fulcro (13)
- # graalvm-mobile (19)
- # helix (2)
- # introduce-yourself (1)
- # jobs (2)
- # jobs-discuss (28)
- # kaocha (9)
- # livestream (11)
- # malli (15)
- # meander (24)
- # nextjournal (8)
- # off-topic (26)
- # pathom (1)
- # pedestal (8)
- # polylith (2)
- # portal (31)
- # re-frame (4)
- # reagent (10)
- # reitit (8)
- # remote-jobs (3)
- # sci (1)
- # shadow-cljs (66)
- # spacemacs (20)
- # testing (6)
- # vim (15)
- # xtdb (7)
In this example:
(.-someProp (first #js [#js {:someProp 1}]))
the CLJS compiler loses the ^js
tag because of (first ...)
and replaces it with #{'any 'clj-nil}
.
This leads to two issues:
ā¢ -someProp
gets renamed during :advanced
compilation
ā¢ There's no "Cannot infer target type" warning
Is it something expected or is it a bug?
If it's expected, how can it be improved so that people become immediately aware of this issue during development?I don't think there's anything we can do here that would be idiomatic to improve anything
but ClojureScript functions can and will erase stuff because in general - you cannot infer much
Hmm, that's unpleasant. Makes relying on the warning pretty much useless - better to type hint every definition and CLJS form involved in interop anyway.
But the analyzer could theoretically infer the tag in this case, no? Although, it would probably have to be a special case for first
and all such functions...
for example this is not a problem if I'm writing ClojureScript and I'm actually using #js
and goog.object
Well, with goog.object
nothing would be a problem indeed, but it's quite cumbersome when you have to do heavy interop.
The example is a simplified version of this actual code:
(defn replace-track-source! [^js playlist track-name src]
(loop [tracks (.-tracks playlist)]
(when-first [^js track tracks]
(if (= (.-name track) track-name)
(-> (to-audio-buffer src playlist)
(.then (fn [audio-buffer]
(let [audio-buffer (audio-util/normalize-volume audio-buffer)]
(set! track -src audio-buffer)
(.setBuffer track audio-buffer)
(.setCues track 0 (.-duration audio-buffer))
(.setPlayout track (doto (Playout. (.-ac playlist) audio-buffer)
(.setVolumeGainLevel (.-gain track))
(.setStereoPanValue (.-stereoPan track))))
(.calculatePeaks track (.-samplesPerPixel playlist) (.-sampleRate playlist))
(.adjustDuration playlist)
(.drawRequest playlist)))))
(recur (next tracks))))))
Notice that ^js track
- without ^js
all track-related fields would be renamed. Simply because when-first
is effectively (let [track (first (seq tracks))] ...)
.With goog.object
, any (.. a -b -c -d)
becomes incredibly more complex. Any function call becomes much less transparent. So I don't think it's a good solution.
Wouldn't the type of (aget #js [cljs] 0)
be inferred as js
?
If no, than how does (aget #js [js] 0)
work, if at all?
OK, I'm just probing the ground here because I would definitely like to have a solution to that. Anything that doesn't require me or anybody else to get burned after a production release or to have an :advanced
build just for that extra check of every related functionality.
Are there any reasonably frequent instances where you would actually want to do JS interop on CLJS data? Maybe an extra [opt-in] warning about dot forms where the tag of the target is clj-any
would be a solution?
Well, that's from cljs.core
or something like that I presume, so that's a special case. After all, you get a lot of Cannot infer target type
warnings from that NS.
@p-himik or any other library that does this, which after 11 years is going to be more than you think
probably the right way to get warning would be to check that property exists at all somewhere
one of the biggest problems with externs-inference was just having to suppress stuff deftype/defrecord
Oh, I'm not talking about "do it now", of course not. If that's something that's reasonable, I might even fiddle around and come up with a patch for that opt-in warning - I just don't want to waste time if that's something that isn't worth doing at all.
Also, I'm not sure whether it's the CLJS compiler that does that, but shadow-cljs documents :infer-externs :auto
- it makes externs-related warnings to appear only for your own files, which is quite handy.
Detection of existing properties would be quite tricky and full of false negatives. I see a lot of code where new properties are created by using string concatenation.
the only that's left is correct collection of cljs.core
properties - to know which ones exist
No, not in cljs.core
- in JS files that I use with CLJS, the sole reason I need so much interop.
Ah, so in "probably the right way to get warning would be to check that property exists at all somewhere" you meant the "Cannot infer target type" warning and not the opt-in warning that I suggested?
So in your example with (.-foo ...)
if that -foo
is something that is indexed from CLJS or GCL, then there would be no warning, it would be considered an internal property that can be minified. And if it cannot be found, then it would be considered external and the warning would be issued?
What about situations where -foo
exists both in CLJS/GCL and in some JS file where it's not supposed to be renamed? A user should definitely be warned in such a case as well, but I'm not sure whether it's feasible.
at least for internal data structures I don't think this will be problem because it's written in such a low level way - either the type is know or could be trivial hinted
though now that you bring it up - the main issue if perfectly legitimate non-interop (deftype) code in some library
Right. So at least to me (a layman when it comes to compilers, really) that opt-in warning about constructs like (.-foo (first ...))
stills sounds like a reasonable solution.
it's worth opening a JIRA ticket about the basic problem - stuff like this usually take some time to really think through all the options
I don't have access right now but I can write the initial version of the issue description if that's helpful.