Fork me on GitHub
#cljs-dev
<
2023-03-28
>
thheller05:03:32

doesn't really matter what hashing approach is used, as long as it produces a proper hash

thheller05:03:56

if there are multiple impls only one ends up getting used, so should all be fine

thheller05:03:28

extending these by default could be a problem for engines where they don't exist

thheller05:03:55

not sure what the state of support is for either

p-himik08:03:58

It does matter, a lot, when two usages of extend-type with different hashing approaches aren't next to each other. Suppose you have

(extend-type js/BigInt
  IHash
  (-hash [this]
    (hash (.toString this 10))))

(def data (into #{}
                (map js/BigInt)
                (range 1000)))

(extend-type js/BigInt
  IHash
  (-hash [this]
    (hash (.toString this 16))))

(dotimes [i 1000]
  (when-not (contains? data (js/BigInt i))
    (js/console.log i)))
Check what the output is.

p-himik08:03:54

Also a very fun thing to discover:

ClojureScript 1.11.60
cljs.user => (extend-type js/BigInt
               IHash
               (-hash [this]
                 (hash (.toString this 10))))
#object[Function]
cljs.user=> (implements? IHash (js/BigInt 1))
true
cljs.user=> (implements? IHash (js/BigInt 0))
false
Perhaps that's why implements? is marked as experimental, dunno.

p-himik08:03:22

> extending these by default could be a problem for engines where they don't exist > not sure what the state of support is for either Is there a list of engines that CLJS aims to support or at least not break needlessly? I'd be glad to check.

2
hifumi12309:03:03

Ditto. One thing I have anecdotally seen a lot in requests are concerns about whether e.g. Google Closure has polyfills for ES5 and older JS versions. It would be nice to see an official list of JS engines that the ClojureScript team actively tries to support. While this is a huge wish, something like FreeBSD’s architecture support would be nice to have for users and developers, alike. Namely, there are three tiers for support: 1 = supported and tested, 2 = niche or experimental support, 3 = unsupported or dropping support soon. Just off a wild guess, I would assume Rhino or Nashorn would probably be classified as “Tier 3” JS engines whereas V8 and JSCore would probably be “Tier 1". Of course, making this list is too much work. So maybe just a flat list of “supported JS engines” is the best approach here.

p-himik09:03:31

And even without such a list, couldn't CLJS simply do something like this?

(when (exists? js/BigInt)
  (extend-type js/BigInt ...))
It already uses a similar approach for js/Symbol and other things, albeit not for extend-type.

thheller11:03:40

I suppose it could. or create a common library to collect these and have other libs depend on that instead of making their own.

p-himik14:03:36

Ah, found the cause of that aforementioned issue with implements? - it passes the last argument as a condition to if(...), which means that it won't work for anything that's false-y in JS.

Sam Ritchie15:03:14

Wow that seems like it could use a patch. So does implements? Fail with empty vectors and 0 as well?

dnolen15:03:07

@p-himik @sritchie09 this is intentional, btw, implements? means you implemented it via deftype/record and it’s something you control

dnolen15:03:50

this was added as a performance optimization primarily and should be used only if you know what you are doing

👍 2
dnolen15:03:41

the primary driver for this is dispatches via cond in the core fns where the order is carefully chosen

borkdude17:03:50

could this be a bug? happy to provide an issue + fix

cljs.user=> (macroexpand '(clojure.core/and))
Unexpected error (IllegalArgumentException) macroexpanding cljs.core/macroexpand at (<cljs repl>:1:1).
Don't know how to create ISeq from: java.lang.Boolean

hifumi12318:03:34

Maybe? Technically macroexpand is doing its job: it is repeatedly calling macroexpand-1, but we end up with a value instead of a form while it is doing so.

hifumi12318:03:05

I am 50/50 on "this is expected behavior" and "this is a bug"

borkdude20:03:09

imo it's a bug, a macro can return anything, lists and non-lists

hifumi12320:03:47

I re-read the docstring and I’m starting to lean more towards “bug”, because the docstring states it will invoke macroexpand-1 “until it no longer represents a macro form”, but the inner loop doesn’t seem to be doing that (otherwise it wouldn’t attempt to call macroexpand-1 on true).

hifumi12320:03:38

Comparing behavior between Clojure and CLJS, and I think it’s a bug. It’s worth posting on Ask Clojure

borkdude20:03:32

@U050B88UR shall I go straight to JIRA for an issue + patch?

dnolen14:03:16

issue + patch welcome, I think probably a oversight from the changes to and / or sometime about

dnolen14:03:22

thus - please check or case as well

borkdude16:03:35

@U050B88UR The issue is more general than and and or. It's about this:

(defmacro foo []
  1)
cljs.user=> (macroexpand '(foo))
Unexpected error (IllegalArgumentException) macroexpanding cljs.core/macroexpand at (<cljs repl>:1:1).
Don't know how to create ISeq from: java.lang.Long
So any macro that doesn't return a seqable will fail. But I'll provide an issue and patch for this

dnolen17:03:30

well that’s good, since then a fix didn’t introduce some regression 🙂

dnolen13:03:48

thanks! made a branch running tests

dnolen15:03:14

resolved, thanks!!!

borkdude15:03:11

🎉 thanks!