Share your thoughts in the 2024 State of Clojure Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in ClojureScript by
This ClojureScript change
https://github.com/clojure/clojurescript/commit/bcf60ce194e5292fbc5c4b2d89dfc5a7b886b94c
tracked this Clojure change
https://github.com/clojure/clojure/commit/20f67081b7654e44e960defb1e4e491c3a0c2c8b

A consequence is that {{int?}} is satisfied by {{goog.math.Integer}} which is not fixed-precision.
Also, it creates a situation where it is possible to have values that satisfy {{int?}} but don't satisfy {{integer?}} or {{number?}}. (Note that this also affects things like {{pos-int?}}.)

I'd propose two alternative approaches to fix this that we can debate:

Alternative A: Simply remove the {{goog.math}} items from {{int?}} and friends.

Alternative B: Have {{goog.math.Long}} values satisfy {{number?}}, {{integer?}}, and {{int?}} and have {{goog.math.Integer}} values satisfy {{number?}} and {{integer?}}.

In either case, the docstrings should be updated.

I'll attached two concrete patches for consideration / debate.

3 Answers

0 votes
by
_Comment made by: favila_

What should be the goal for the various numeric predicates in CLJS?

Is the goal to align with CLJ's meaning of these predicates? If so then:
{{number?}} true for typeof-number or goog.math.Integer or goog.math.Long
{{integer?}} true for goog.math.isInt/Number.isInteger or goog.math.Integer or goog.math.Long
{{int?}} true for goog.math.isInt/Number.isInteger or goog.math.Long

Is the goal to align with some notion of platform-primitiveness? If so then:
{{number?}} true for typeof-number or goog.math.Integer or goog.math.Long
{{integer?}} true for goog.math.isInt/Number.isInteger or goog.math.Integer or goog.math.Long
{{int?}} true for goog.math.isInt only

Is the goal to be a can-I-do-arithmetic-with-this type check? If so then:
{{number?}} true for typeof-number only
{{integer?}} true for goog.math.isInt (or maybe even Number.isSafeInteger)
{{int?}} same as integer?


In Java/CLJ these three goals are much more aligned with one another. Any number-as-identifier can also be used for clj arithmetic (so the widest check, {{number?}}, can also be used for arithmetic checking), and {{int?}} corresponds exactly to the host's most-primitive integer value-types (vs object-type).

CLJS lacks a number tower so it's more interesting.
Right now in CLJS {{number?}} appears to be designed as a predicate to test for whether arithmetic is possible, so it only allows js type-of===number. {{integer?}} is also an arithmetic check, but wants a non-fractional number (interestingly, still allowing unsafe integers, i.e. outside Number.MAX_SAFE_INTEGER, where normal integer arithmetic doesn't work--perhaps it should only allow safe integers).  {{int?}} doesn't care about arithmetic, but it's still useful for seeing if a value could be a numeric identifier (e.g. a record id received via transit); but that's expressly *not* what CLJ's int? cares about.

0 votes
by
_Comment made by: mfikes_

The attached A and B patches explore the two approaches.

Patch A could probably be applied as it exists now.

Patch B on the other hand seems to have lots of consequences related to whether something that satisfies {{number?}} can participate in arithmetic or be used in other places where numbers are currently used. I suspect we could make all of this work but we'd be giving up a lot of perf.

As one concrete example: Is this a valid program, and should it return {{true}}?


(zero? goog.math.Integer/ZERO)
0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJS-2921 (reported by mfikes)
...