Fork me on GitHub
#cljs-dev
<
2018-07-13
>
dnolen00:07:05

I recall maybe a couple of reports but that’s because people wanted it to be treated specially

dnolen00:07:13

but I more or less rejected that

dnolen00:07:25

since we coerce to nil I don’t think anybody notices

mfikes01:07:40

I ran into that sort of question when thinking about the construct

(when-not (nil? x) x)
which yields a value identical to nil when x is js/undefined. (I had hit this in the first change here https://github.com/clojure/clojurescript/commit/892ed2029db42cc3728e6e99a37d99b4ec53ecc0 and ended up concluding that perhaps that construct was in use prior to js/undefined and nil being equivalent.) The only other place where I've seen this concept is that js/undefined appears for unbound vars. https://github.com/clojure/clojurescript-site/pull/228

mfikes01:07:42

Of perhaps historical interest, p. 32 of ClojureScript: Up and Running has > What is logical true? In ClojureScript, nil, false, and the undefined value (written js/undefined) are logical false, and anything else is logical true. While this seems to imply 3 false values, perhaps this is older than the stance of treating JavaScript null and js/undefined as equivalent to ClojureScript nil. On p. 42 it has a bit more > ClojureScript's nil is identical to null in JavaScript; it is used where a value is logically absent, empty, or meaningless. To use it as a literal, just use the special symbol nil. ClojureScript does not use JavaScript's undefined value, but you can refer to it as js/undefined. Again, while arguably "accurate," this text seems to either predate the unification of null and undefined, or it chose to gloss over it (or was simply unaware).

mfikes02:07:33

TL;DR, though, I've also never seen any need to care about js/undefined

dnolen02:07:22

yeah can’t remember who decided to treat undefined as nil, it might have been before myself, whatever the case it was definitely done in the first year

dnolen02:07:07

Up & Running came out pretty early and was probably already falling behind 😛

ambrosebs04:07:06

and looks like undefined is logically false since commit 0

Roman Liutikov09:07:55

Is this difference between cljs and clj expected?

;; clj
(defprotocol HTML
  (to-html [this]))

(extend-protocol HTML
  clojure.lang.ISeq
  (to-html [this] "html"))

(to-html (range 10)) ;; this works
;; cljs
(defprotocol HTML
  (to-html [this]))

(extend-protocol HTML
  ISeq
  (to-html [this] "html"))

(to-html (range 10)) ;; this doesn't work
;; No protocol method HTML.to-html defined for type cljs.core/Range
;; but `(implements? ISeq (range 10)) ;; true`

Roman Liutikov09:07:46

If yes, then how the same can be achieved in ClojureScript?

mfikes11:07:58

The same sort of issue arises with defmulti /`defmethod`: While hierarchies based on keywords are honored, if you use type there is no type hierarchy in the ClojureScript side to make use of. Perhaps this all should be documented on https://clojurescript.org/about/differences

mfikes14:07:24

If you look at the implementation of isa? in ClojureScript, you can see that the type inheritance aspect is commented out. I wonder, is the "JavaScript type inheritance relationship" mentioned in the isa? docstring just a result of replacing "Java" with "JavaScript" when doing the port? (Or is there perhaps an intent to try to support something here in the future?)

dnolen14:07:00

@roman01la not supported - you can simulate it with extend-type default and handling it there

Roman Liutikov14:07:38

@dnolen thanks! could there be a warning or something that tells it’s not supported?

dnolen14:07:20

we might revisit it later - but not a priority and not interested in a warning about it

ambrosebs15:07:24

what makes this harder to implement in JS?

ambrosebs15:07:51

that "cljs differences" page says boxed booleans are irrelevant to if. But there's still the same behaviour in CLJS as CLJ (I think?).

cljs.user=> (if (js/Boolean. false) 1 2)
1
cljs.user=> (if (.valueOf (js/Boolean. false)) 1 2)
2

ambrosebs15:07:39

huh, also this evaluates to 2 in CLJ

cljs.user=> (if (boolean (js/Boolean. false)) 1 2)
1

ambrosebs15:07:10

just a curiosity obviously 😛

dnolen15:07:26

@ambrosebs re: extending a protocol - no interfaces that’s the only reason it works in Clojure

dnolen15:07:50

you can also run into problems via AOT if I recall

dnolen15:07:58

extending the protocol is not safe - interface works

dnolen15:07:29

@ambrosebs constructing Boolean String Number etc. is a disaster on JVM & JS

dnolen15:07:35

should be avoided

ambrosebs17:07:28

I'm learning about how JS's new works. Am I right in saying these are the common kinds of values used as ctors in CLJS? 1. JS built-ins 2. deftype's 3. something annotated as @constructor in GClosure

ambrosebs17:07:54

In particular, you normally wouldn't write a defn that's actually a ctor, right?

thheller17:07:10

@ambrosebs you kinda have to use defn with manually annotated @constructor in cases where you need inheritance. eg. extends React.Component

thheller17:07:31

since that is not supported by deftype it gets done via defn manually

ambrosebs17:07:30

I see, thanks! is this pattern ever used by normal users?

thheller17:07:01

I think every react wrapper has some hack like this. in typical user code I'd guess its much rarer

thheller17:07:32

although I have done it once or twice so it does happen