This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-02-25
Channels
- # announcements (5)
- # beginners (74)
- # boot (5)
- # cider (57)
- # cljdoc (5)
- # cljs-dev (45)
- # clojure (37)
- # clojure-dev (6)
- # clojure-europe (4)
- # clojure-italy (17)
- # clojure-nl (11)
- # clojure-spec (48)
- # clojure-uk (96)
- # clojurescript (79)
- # cursive (17)
- # data-science (1)
- # datomic (27)
- # emacs (2)
- # fulcro (22)
- # immutant (1)
- # java (62)
- # juxt (4)
- # kaocha (4)
- # lein-figwheel (5)
- # leiningen (6)
- # midje (1)
- # mount (1)
- # music (3)
- # nrepl (6)
- # off-topic (49)
- # pathom (10)
- # pedestal (2)
- # re-frame (43)
- # reagent (2)
- # ring (2)
- # shadow-cljs (78)
- # spacemacs (6)
- # test-check (2)
- # tools-deps (4)
I’ve been digging through the emitted code for various js-interop examples, and was surprised to find that CLJS does not seem to “know’ that goog.object/containsKey
returns a boolean value, and so when it is used in an if
statement it is wrapped in a truth_
check unless one adds a type hint. But thinking about it, I suppose it makes sense that there is no upward flow of type information from js -> cljs
what if you wrap it with a cljs function which does explicit type hints, would it ruin advanced compilation inlining?
(defn ^boolean containsKey [obj k]
(gobj/containsKey obj k))
^ compiles to the inlined output of gobj/containsKey
without wrapping in truth_
FWIW, gleaning type hint information from Closure is an idea that has been discussed (worth pursuing). See this bit of logic David worked out https://github.com/clojure/clojurescript/blob/f97d766defd02f7d43abd37e3e9b04790a521b1e/src/main/clojure/cljs/externs.clj#L165-L172
is there some kind of special handling of the goog.reflect
namespace that changes how it is included/required? if I emit (~'goog.reflect/objectProperty ...)
from a macro and use it from another namespace, I get warnings like
WARNING: No such namespace: goog.reflect, could not locate goog/reflect.cljs, goog/reflect.cljc, or JavaScript source providing "goog.reflect" at line 21 /../js-interop/src/test/applied_science/js_interop_usage.cljs
WARNING: Use of undeclared Var goog.reflect/objectProperty at line 21 /../js-interop/src/test/applied_science/js_interop_usage.cljs
(despite properly requiring goog.reflect
in the cljs namespace which self-requires its same-named macro ns)
as a workaround I am using js/goog.reflect.objectProperty
instead, but when compiling in :advanced mode that results in warnings related to externs inference:
WARNING: out/test-2/inferred_externs.js:14: WARNING - name goog is not defined in the externs.
goog.reflect;
^^^^
Feb 25, 2019 12:25:31 PM com.google.javascript.jscomp.LoggerErrorManager println
WARNING: out/test-2/inferred_externs.js:15: WARNING - name goog is not defined in the externs.
goog.reflect.objectProperty;
^^^^
I think your issue is this https://github.com/appliedsciencestudio/js-interop/blob/master/src/main/applied_science/js_interop.clj#L6
if you just emit a direct call to (goog.reflect/objectProperty ...)
in the macro it should work?
oh. why would that cause a problem? I thought (~'some-symbol)
would be equivalent to (def x 'some-symbol) ~some-symbol
. at least it seems to behave that way everywhere else
does the warning go away if you use goog.reflect/objectProperty
here directly instead of the ~reflect-property
? https://github.com/appliedsciencestudio/js-interop/blob/master/src/main/applied_science/js_interop.clj#L41
yeah it behaves the same if i write (~'goog.reflect/objectProperty ~(dot-name k) ~obj)
ie. i also can’t call a function from the cljs namespace without using a quoted fully qualified symbol
(defn wrap-key
"Convert key to string at compile time when possible."
([k]
(wrap-key k nil))
([k obj]
(cond
(or (string? k)
(number? k)) k
(keyword? k) (name k)
(symbol? k) (cond (= (:tag (meta k)) "String") k
(dot-sym? k) `(goog.reflect/objectProperty ~(dot-name k) ~obj)
:else `(wrap-key ~k))
:else `(wrap-key ~k))))
that is also why i use (def lookup-sentinel 'applied-science.js-interop/lookup-sentinel)
. I can’t just use lookup-sentinel
because it doesn’t exist for clj
a very handy change in cljs macro behaviour would be to have clj not warn on vars that are defined in the same-named cljs namespace
(ns hello-world.core
(:require-macros [hello-world.core :refer (x)])
(:require [goog.reflect]))
(prn (x {}))
(ns hello-world.core)
(defmacro x [thing]
`(goog.reflect/objectProperty "prop" ~thing))
yes, this only shows up if you require hello-world.core
from a 3rd namespace which does not explicitly require goog.reflect
earlier i wrote some examples comparing goog.reflect
and goog.object
and using the same syntax/structure with goog.object
doesn’t cause any issues
i pushed that example here: https://github.com/mhuebert/cljs-goog-reflect/tree/master/src/reflect
it happens because https://github.com/clojure/clojurescript/blob/179ee9018e448a716d3c3fc0db5c2ed967a53ae1/src/main/clojure/cljs/analyzer.cljc#L877 doesn't check the namespaces provided by the closure lib
yeah. should be an easy fix. I'm unsure where CLJS stores the closure namespaces though, if it does at all.
I think the above is a good reason to push ahead on the parsing Closure namespaces