Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?

Implicit integers for JavaScript

This proposal is an alternative to “Integer: Arbitrary precision integers in JavaScript” by Daniel Ehrenberg, but it also builds on his work.


Everything mentioned here is work in progress. It is not sure that these ideas will work out:

  • They may break the web.
  • They may turn out to be too complicated/user-unfriendly.

Rationale

The current proposal for Integers with arbitrary precisions has pros and cons:

  • Pros: It is very clean and paves the way for more operator overloading and user-definable value types in the future.
  • Cons: It is only partially backward-compatible. The already existing implicit “small integers” (incl. array indices, Array#entries(), Array#forEach(), etc.) clash with the new “big integers”.
    • That is, you can’t tell developers: “Use Integers whenever you can.”
    • Instead, best practices are: “Use Numbers for up to 53-bit ints. Use Integers if you need more bits.”

This proposal sketches an alternative approach. It has different pros and cons.

Number is a supertype of Int and Double

Number is a supertype of Int and Double: Number = Int ∪ Double

  • Double:
    • typeof 123.0 === 'number'
    • Number.isDouble(123.0) === true
    • Converting to Double: Number.asDouble()
  • Int:
    • typeof 123 === 'number'
    • Number.isInt(123) === true
    • Number.isInt(0xFF) === true
    • Converting to Int: Number.asInt()

More tool functions:

  • Number.parseInt() : Int (new signature)
  • Number.asUintN(width, theInt) (works as described in Dan’s proposal)
  • Number.asIntN(width, theInt) (works as described in Dan’s proposal)

Operator overloading

Binary operators

Existing binary operators for numbers are overloaded:

  • +, -
  • *, /, %, **
  • <<, >>, >>>

Signature:

  • Signatures where results are Double:
    • Int × Double → Double (via coercion)
    • Double × Int → Double (via coercion)
    • Double × Double → Double
  • Signature where the result has arbitrary precision:
    • Int × Int → Int (all operators except /, see below)

Additionally, new Int-only operators (signature: Int×Int→Int) are introduced:

  • Integer division: div
    • Normal division must produce non-integer values, e.g. for 1/2
  • Bitwise operators: band, bor, bxor
  • Shift operators: shl, shr

Open question: Will + and * having more precision for Ints break code on the web? For example:

  • Currently: 9007199254740992 + 1 === 9007199254740992
  • With this proposal: 9007199254740992 + 1 === 9007199254740993

Equality

  • With this proposal, === has to coerce if a Double has no decimal fraction: 1.0 === 1

Bitwise operators

The results of bitwise operators stay within 32 bits and are of type Int.

Unary operators

  • Unary + must coerce to Double, because, among others, asm.js depends on it.
  • Unary -: it is unclear how this operator can be made to work for Ints (which only have a single zero), given that:
    • Object.is(-0, 0) === false

Open questions

  • Int operators: coerce or throw exception if operand types are wrong?
  • Naming: Int makes most sense, given Number.isInteger() etc.

Various thoughts

  • Static type checking tools could warn if the operands of a numeric operator mix numbers and integers.
  • JSON would automatically get big integer values (more than 53 bits).

Further reading

Deciding that 1 is now an integer is a backwards-incompatible change.
Code could expect two integers being multiplied to end up being a truncated float.

ljharb commented Mar 30, 2017

@FremyCompany can you show me some code that would depend on that? (recognizing that they'd have to be multiplying integers such that the result is larger than MAX_SAFE_INTEGER, and then relying on that value being wrong)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment