rescript-compiler icon indicating copy to clipboard operation
rescript-compiler copied to clipboard

Add BigInt primitive number type

Open Bubbler-4 opened this issue 3 years ago • 10 comments

I'm surprised no one suggested this yet (the only other relevant issue I could find was #2903). Now that all major browsers and runtimes support it (ignoring IE which is EOL'd anyway), I guess it's about time to add it as a primitive number type.

  • BigInt literals 1n, 9007199254740991n
  • Conversion from/to strings/ints/floats
  • Binary operators and/or built-in functions for arithmetic on bigints, e.g. + - * / ** %

(The MDN doc shows a couple static functions too, but they're not yet supported on Safari, and I don't think they're that useful.)

Bubbler-4 avatar Sep 07 '20 06:09 Bubbler-4

indeed, it's something we should add. note 3n has a special meaning in ocaml, it's nativeint. Shall we choose a different suffix or just override it. If we use n as a suffix, we need check if we can make this works:

let f = function 
  | 1n 
  | 2n -> 0
  | x -> Nativeint.add x 3n

bobzhang avatar Sep 10 '20 10:09 bobzhang

We don't need a special literal imho. BigInt(1) is the same as 1n in JS. It can be done purely with bindings, say, a Js.BigInt module. Js.BigInt.ofInt, ofString, etc., can be constructors.

yawaramin avatar Jun 15 '21 13:06 yawaramin

i feel like special literals would be better (like %re) so we could transpile to, say, 10000000000000n nicely

somebody1234 avatar Sep 19 '21 21:09 somebody1234

It would make it perhaps slightly more convenient to do e.g. %bigint(10000000000000) instead of BigInt.ofString("10000000000000"), I just don't know if it's worth the tradeoff of implementing custom support in the compiler as opposed to just writing a library-level binding.

yawaramin avatar Sep 20 '21 13:09 yawaramin

@yawaramin it would also be possible to avoid having to allocate a string - not that there's a noticeable difference in perforamance very much of the time, but i do believe it'd be slightly more idiomatic? idk

somebody1234 avatar Sep 20 '21 13:09 somebody1234

This proposal is sorely needed IMO, we at least need a single type in pervasives for libraries to target to as a first step.

We don't need a special literal imho.

I disagree, literals are much more intuitive and much less error prone. ofString would have to be used everywhere which is a really frustrating experience when coming from JS.

Another +1 for why this is needed, Temporal will be landing in the coming months and parts of the API rely heavily on bigints: https://tc39.es/proposal-temporal/docs

Compiler support would be great also for output size - BigInt("100000") vs 100000n. You could argue that compression negates this point, but that only helps in bundles.

tom-sherman avatar Dec 30 '21 11:12 tom-sherman

@somebody1234 aren't strings interned by JS runtimes nowadays? And in any case, I doubt that calling the constructor like BigInt("1") would allocate a string.

@tom-sherman anyone can send a PR for at least initial BigInt bindings even without a custom literal syntax. Just need to create a new module Js.BigInt, put the t type and the rest of the bindings in there.

About 'frustrating experience', I'm not really seeing how it's worse than having to use e.g. React.string etc. ReScript is a little bit more explicit than JS/TS in return for being much more type-safe. and if typing out BigInt.ofString is a burden, then it's easy to do let b = BigInt.ofString, which also resolves the output size issue, not that it should be a serious issue in the first place if people are correctly using HTTP compression to deliver JS and other payloads in production settings.

yawaramin avatar Dec 30 '21 23:12 yawaramin

The ofString function introduces room for runtime errors though, errors that should be caught at compile time. It also requires the developer to be aware of the edge cases of string->bigint conversions, which can lead to very unexpected results. This is mental overhead that can all be avoided with a literal.

tom-sherman avatar Dec 31 '21 00:12 tom-sherman

@yawaramin interned... sure. whether the runtime would optimize that into a bigint constant... i don't know.

of course as i basically mentioned before, it'd also be more "idiomatic" - as in, in js nobody uses BigInt("string literal") since bigint literals are a thing. therefore including bigint literals would result in more conventional output.

somebody1234 avatar Dec 31 '21 01:12 somebody1234

@tom-sherman OK but the parsing of the literal has to happen somewhere. Making it compile-time in ReScript would mean duplicating the BigInt literal parsing functionality that already exists in the JavaScript platform, making sure to duplicate all its possible quirks and edge cases, and keeping those up-to-date, otherwise when people run into edge cases they will be super confused why ReScript BigInt literal parsing behaviour is different than vanilla JS (small example that we can already see: ReScript parses 1. as a valid float).

Anyway, whether that's done or not, all I'm saying is that the Js.BigInt module is needed anyway, and it will be much easier to implement than compile-time BigInt literal parsing. So perhaps some interested party can work on that, at least.

yawaramin avatar Dec 31 '21 02:12 yawaramin

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Mar 13 '24 08:03 stale[bot]

Too eager, stale bot! https://github.com/rescript-lang/rescript-compiler/pull/6670

fhammerschmidt avatar Mar 13 '24 09:03 fhammerschmidt

Resolved #6670

mununki avatar Mar 27 '24 12:03 mununki