Fork me on GitHub
#clojurescript
<
2018-01-12
>
ajs13:01:43

is there any reason to prefer (.log js/console "hi") over (js/console.log "hi") ?

the-kenny13:01:43

no. Some people just dislike the dot-notation

mfikes17:01:09

@ajs If you dig into the dot notation subject, an argument could be made that js is a pseudo-namespace and the symbol console.log is an abuse that embeds JavaScript nested property syntax into ClojureScript code. But perhaps this is the ClojureScript analog of the legitimate use of dots in symbols in Clojure to designate fully-qualified class names, and is really nothing more than "interop" (a pragmatic view, opposed to a prescriptive or pedantic one.) A (perhaps fallacious) argument is that all this is OK because Rich is employing that very construct here https://github.com/clojure/clojurescript/commit/954e8529b1ec814f40af77d6035f90e93a9126ea#diff-a9cce52f0bf5a7b9afccbec54e4a0e4bR39

noisesmith17:01:05

my response when I see (js/console.log ...) is "what? why? how? that's not even a valid clojure symbol!"

noisesmith17:01:23

but I knew clojure for a while before learning cljs so it might be that I'm just a grouchy old man

mfikes18:01:46

@noisesmith Yes. Consistency in the idioms employed between ClojureScript and Clojure can be a good thing. I had the same reaction initially as well. My story was that ClojureScript allowed me to, starting from knowing Clojure, produce a JavaScript app while not knowing JavaScript.

mikerod18:01:32

That sort of dotted notation confused me too - as a clj concept that is

mikerod18:01:36

similarly weird to me was seeing something like (.-target.value e)

mfikes18:01:03

Ugh. Is that legit? Yikes.

mikerod18:01:24

I guess? hah

mikerod18:01:32

I’ve used it just from seeing it as an example elsewhere

mikerod18:01:48

I probably should understand why it ok better. I briefly thought about it once then forgot

mikerod18:01:17

I guess you should do (.-value (.-target e)) to be more clj-like

mikerod18:01:34

or .. or thread, sugar, etc

mfikes18:01:52

Yeah. (.. e -target -value) would be cool too.

mfikes18:01:11

But that frankenstein thing feels like two languages mixed in one.

mikerod18:01:29

Can js/console.log be written as? (.log js/console)?

mikerod18:01:32

I guess I haven’t tried

mfikes18:01:00

Sure, but you need to call it. ((.-log js/console) "hi")

mikerod18:01:35

I removed the hyphen

mikerod18:01:44

then it calls it

mfikes18:01:30

On a pragmatic note, there was a recent case (trying to recall the details), where, if you avoid playing these interop games, and write code that is "Clojure", then the ClojureScript analyzer can help avoid some mistakes you might make.

mikerod18:01:09

There is actually this blog: http://www.spacjer.com/blog/2014/09/12/clojurescript-javascript-interop/ that went into some depth on these “frankenstein lang” interop forms I belive. Been a while since I read it and not sure how dated it is now since it was from a while back.

mikerod18:01:49

That’d be cool to see a case where you made more “Clojure” code to get analyzer benefits. Your next blog post perhaps?! 😛

mfikes18:01:12

I'll try to recall the example. It was a simple one, where you are left scratching your head as to why it doesn't work. I recall it being fairly easy to see why if you look closely at the code, but if you were to just write it without dots then the analyzer just "tells you".

mfikes18:01:25

@mikerod The example was (fn [_] ,,, (js/_.debounce ,,,)) not working.

mfikes18:01:15

If instead you write (fn [_] ,,, (.debounce js/_ ,,,)) then the analyzer throws you a bone:

WARNING: js/_ is shadowed by a local at line 1

noisesmith18:01:23

cool! - glad to have a proper argument to back up my stodgy preference 😄

mfikes18:01:09

Yeah, in our current conversation

((fn [console] ,,, (js/console.log "hi")))
produces a pause-inducing
undefined is not an object (evaluating 'console.log')
while
((fn [console] ,,, (.log js/console "hi")))
gives you a clue:
WARNING: js/console is shadowed by a local at line 1
undefined is not an object (evaluating 'console.log')

mfikes18:01:04

My grouchy old-man beard just grew a little. 🙂

mfikes18:01:49

For those interested, the older conversation on this subject was here https://clojurians-log.clojureverse.org/clojurescript/2017-10-27.html

mikerod18:01:28

@mfikes nice. these are good examples to know

mfikes18:01:10

Yeah, it is consistent with the view that, by doing js/foo.bar.baz, you are really writing JavaScript and bypassing the analyzer.

mikerod18:01:52

I had no idea about the shadowing things.

mikerod18:01:05

That makes sense that when you start writing what doesn’t even look like cljs, that it may bypass

mikerod18:01:30

intuitively. I think I’m going to try to stick to avoiding that sort of syntax more than I have before.

mikerod18:01:41

In the blog I posted earlier: http://www.spacjer.com/blog/2014/09/12/clojurescript-javascript-interop/ there is a section (can’t link) called “Nested scopes” There it is shown a case where this “dotted access” pattern seems necessary.

mikerod18:01:06

Based on the example there, if you want the JS:

var m = new Microsoft.Maps.Map();
You use CLJS:
(def m (js/Microsoft.Maps.Map.))

mikerod18:01:26

It’s a constructor, so it you can’t do

(def m (new (.-Map (.-Maps js/Microsoft)))) 
or something like that (or with .Map (no hyphen))

mfikes18:01:40

Yeah, interestingly, I think you can get away with

(def m3 (let [ctor (.. js/Microsoft -Maps -Themes -BingTheme)] (new ctor))
but I think this is a different abuse.

mikerod18:01:47

That is surprising looking to me at least

mikerod18:01:06

I guess if it were officially supported, it’d solve the dilemma of the syntax

mfikes18:01:43

@mikerod In terms of new with the dotted symbol, I believe that is at least treading on thick ice with https://dev.clojure.org/jira/browse/CLJS-697

mikerod19:01:42

@mfikes Yep, looks somewhat similar