Fork me on GitHub
#cljs-dev
<
2022-02-15
>
mikerod00:02:38

Do 1.11.x of cljs means it is aligned to 1.11.x of clj right?

neumann19:02:00

I posted here previously about an issue with extern inference. I did more digging, and I have some follow-up information for anyone interested. The following code does not produce an extern for MediaDevices. Note the lack of js/:

(defn on-device-change!
  [callback]
  (let [^MediaDevices media-devices (.-mediaDevices js/navigator)]
    (set! (.-ondevicechange media-devices) callback)))
If I add the js/ to be ^js/MediaDevices, ClojureScript does infer and generate the extern, but I also get a warning:
Cannot resolve property ondevicechange for inferred type js/MediaDevices in expression (. media-devices -ondevicechange)
Although the ondevicechange attribute is part of the W3C spec and supported by browsers, it is not listed in the pre-defined set of externs in Closure Compiler: https://github.com/google/closure-compiler/blob/master/externs/browser/w3c_rtc.js#L1527 This ClojureScript warning only appears to happen in this situation: the Closure Compiler includes externs for the class, but is missing the specific property/method that needs to be inferred.

neumann19:02:30

This is with ClojureScript 1.11.4.

thheller19:02:41

without the js/ in the hint you are basically telling the compiler this class is safe to get renamed, since it assumes it is a CLJS/Closure class

thheller19:02:54

pretty sure the closure externs are missing that property since you are normally expected to use addEventListener to add events?

neumann19:02:16

Good to know about the js/ hint. That makes sense.

neumann19:02:49

addEventListener is also part of the spec and is often recommended over the attribute, but there are still advantages of using the attribute.

neumann19:02:06

Eg. you don't have to track callback references to unregister them.

neumann19:02:33

But I'm guessing that's why Google didn't include the attribute in their definitions.

neumann20:02:40

When I posted about this the first time, I was running into a situation where I had an older version of ClojureScript that pulled in an older set of externs. I was calling a method that had been added to browsers more recently. It's the same kind of problem: incomplete externs in the Closure Compiler generate a warning on inference.

neumann20:02:07

Is this something I should open an issue for? Sorry for my ignorance. I'm not totally sure what to do with this information aside from posting here.

dnolen20:02:24

@neumann but what is the problem? it sounds resolved?

neumann20:02:55

@dnolen The main problem is that the warning is confusing and steers one in the wrong direction. The compiler is generating the same warning as if the type hint doesn't exist at all. Even though adding the type hint does the right thing (infers the extern), it still feels broken (identical error to no type hint). Worse yet, by dropping the js/, the warning will go away (feels fixed), but no extern is generated (actually broken).

dnolen20:02:03

type hints aren't really a thing in ClojureScript - they exist most for internals reason

dnolen20:02:12

no documentation exist that talks about them as far as I'm aware

dnolen20:02:33

the docs for externs inference talks about js/Foo I'm pretty sure

dnolen20:02:17

Closure externs are missing this thing - we warn about it because of typos

dnolen20:02:27

against well known APIs

dnolen20:02:52

it's not immediately clear to me what should be reported in this case

neumann20:02:26

I, personally, got thrown off by String example in the https://gist.github.com/swannodette/4fc9ccc13f62c66456daf19c47692799. But, like you say, the docs always use js/.

neumann20:02:49

It would be extremely helpful if the warning that was generated by having no hint whatsoever was different than having a hint for an attibute/method that wasn't found in the set of externs the compiler knows about.

dnolen20:02:49

that is what this warning Cannot resolve property ondevicechange for inferred type js/MediaDevices in expression (. media-devices -ondevicechange) does

dnolen20:02:18

I don't see how it can be the same if you drop the hint?

dnolen20:02:30

(I'm not shooting down the idea that this can't be improved)

dnolen20:02:36

I just don't see what you are saying

neumann20:02:57

It is in this situation. Here, I'll paste for reference. Without:

[Figwheel:WARNING] Compile Warning   /home/enigma/Devel/Hypersignal/platform/ui/src/cljs/app/api/web/media.cljs   line:52  column:11

  Cannot resolve property ondevicechange for inferred type js/MediaDevices in expression (. media-devices -ondevicechange)

  47    (= (.-name err) "NotAllowedError"))
  48
  49  (defn on-device-change!
  50    [callback]
  51    (let [media-devices (.-mediaDevices js/navigator)]
  52      (set! (.-ondevicechange media-devices) callback)))
                ^---
With:
[Figwheel:WARNING] Compile Warning   /home/enigma/Devel/Hypersignal/platform/ui/src/cljs/app/api/web/media.cljs   line:52  column:11

  Cannot resolve property ondevicechange for inferred type js/MediaDevices in expression (. media-devices -ondevicechange)

  47    (= (.-name err) "NotAllowedError"))
  48
  49  (defn on-device-change!
  50    [callback]
  51    (let [^js/MediaDevices media-devices (.-mediaDevices js/navigator)]
  52      (set! (.-ondevicechange media-devices) callback)))
                ^---

dnolen20:02:33

@neumann ah but what you think is happening is not happening 🙂

dnolen20:02:37

both cases are identical

dnolen20:02:52

externs inference knows about top level singletons and their types

neumann20:02:05

Oh! The js/navigator!

neumann20:02:29

OK. So it was able to infer the js/MediaDevices type without the annotation. I felt like I was adding information, but I wasn't because the compiler already knew that.

dnolen20:02:44

that's correct

dnolen20:02:48

sorry wasn't trying to be obtuse

dnolen20:02:22

to clear when I worked on externs inference

dnolen20:02:30

it was clear users would access web top levels

neumann20:02:36

Oh, I didn't read that as obtuse at all! I appreciate it! I just wanted to confirm my understanding. 😄

dnolen20:02:46

might was well infer the types through Google Closure externs since it's already there

dnolen20:02:48

saving the user type hints

neumann20:02:31

Yeah, the externs inference you added is super helpful! I really like that it can track the type. Awesome stuff! I got hooked on aget and later on oget years ago, and this last year I decided to switch to externs inference.

💯 1
neumann21:02:30

I'm not totally sure why I got confused. I'm going to think about it and re-look at the docs and see if there might be an example or clarification that would have helped me. It looks like there is a "Cannot resolve property" example. If something strikes me, I'll report back. I really appreciate you clarifying! I know you have a ton on your plate.

dnolen21:02:13

Sounds good

neumann23:02:02

Is there any way to avoid that warning? The ondevicechange attribute is a valid attribute, and by using it, I'm stuck with a "Cannot resolve property" warning on every compile. If I set the hint as ^js/FooBar, I don't get any warning and the ondevicechange attribute isn't mangled by the Closure Compiler, but that feels very much like a hack. Using ^js/Object still gives me a warning.