Fork me on GitHub
#cljs-dev
<
2023-09-26
>
dnolen01:09:38

fairly low impact, as there's no direct reference to BigInt anywhere and you have to configure Closure to handle it

dnolen01:09:18

but if you set it up - it's pretty cool, 1N or Long constant values bigger than JS max safe integer values - are emitted as BigInt

dnolen01:09:39

I did a quick pass to make sure that equiv / hashing works as expected

dnolen01:09:12

I pondered the Clojure numeric tower a bit - but after writing pages and pages of notes - I'm not so convinced about creating confusion about numerical interop

dnolen01:09:05

in the end JavaScript only really has Number (Double) and BigInt - trying to pretend otherwise just seems more like more trouble at the moment

dnolen01:09:40

still need to fix tools.reader but I think this is probably an easy one

dnolen01:09:26

re: numeric tower, my primary thought is that Ratio really exists because of Java loss of precision when dividing primitive integral types - however JS choice to use Double was more or less a simplification to avoid that particular footgun from the start

hifumi12302:09:51

hmm i dont understand the latter bit, doesnt JS also have loss of precision in that case? The way I understand Clojure’s Ratio is that it defaults to BigInt to simplify the types involved with rationals. e.g. in Common Lisp, the numerator and denominator of a rational is the integer type, which includes everything from bits to bignums, so forms like (+ 1/2 1/2) will evaluate to a value of type bit. I assume the choice of BigInt in Clojure is to have this sort of flexibility (though there is no way to statically determine if a part in a Clojure ratio may be represented with a fixnum, i.e. the most we can assume out of (+ 1/2 1/2) in clojure is that we have a BigInt )

hifumi12302:09:51

hmm i dont understand the latter bit, doesnt JS also have loss of precision in that case? The way I understand Clojure’s Ratio is that it defaults to BigInt to simplify the types involved with rationals. e.g. in Common Lisp, the numerator and denominator of a rational is the integer type, which includes everything from bits to bignums, so forms like (+ 1/2 1/2) will evaluate to a value of type bit. I assume the choice of BigInt in Clojure is to have this sort of flexibility (though there is no way to statically determine if a part in a Clojure ratio may be represented with a fixnum, i.e. the most we can assume out of (+ 1/2 1/2) in clojure is that we have a BigInt )

dnolen02:09:58

this is true, but defaulting to Double in JS prevents basic nasty stuff like 1/2 and then doing some say iteration bounding on that result

dnolen02:09:53

the big problem for numeric tower is that in JS you cannot generically combine BigInt and Number

dnolen02:09:34

Clojure's numeric tower could be summarized Long -> BigInt -> Ratio -> Double -> BigDecimal I think.

dnolen02:09:54

but this sequence makes things kind of difficult in JS

dnolen02:09:07

first off there is no integral type in JS (except BigInt) nor anyway to figure it out

dnolen02:09:19

the other thing which is practical is that the numeric tower in Clojure involves a lot of code and everything references everything

dnolen02:09:26

which is a dead code elimination hole

hifumi12302:09:29

re: bigint: ah right, numbers are technically all doubles, and integers go up to whatever the length of a double’s mantissa is… so we cant just promote Number to BigInt when mixing them like in Java, or else we could be taking in a number with a fractional part and lose it

dnolen02:09:50

I would say it's even worse that, JS is not really doubles and integers, only doubles

hifumi12302:09:50

in that case i think youre right that cljs should just stick with the js limitations and not try to brush it over

dnolen02:09:05

but semantically you can clamp JS to 32bit ints

dnolen02:09:22

but again you cannot figure this out really - no tagging

dnolen02:09:15

can't just wrap everything to gain tagging w/o creating an interop nightmare

dnolen02:09:58

one escape hatch is Symbol @@toPrimitive - but still, can't combine w/ JS math libs then

dnolen23:09:15

experimenting with a wrapper type that uses @@toPrimitive

dnolen23:09:48

this makes using 1N values not fail when calling into the core apis - i.e (range 5N) etc.