Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

10. Numeric model: separate int and float, / is true division, checked overflow

  • Status: Accepted
  • Date: 2026-09-02

Context

Number handling is one of the highest-leverage decisions in a dynamic language. Choices: one number type (float64, like JavaScript/Lua 5.1) or two (int + float); what / does; and what happens on integer overflow.

Decision

  • Two numeric types. int is a signed 64-bit integer. float is an IEEE-754 double. A literal with no . and no exponent is an int; otherwise a float.
  • Arithmetic promotes. int op int stays int (except /); if either operand is float, the other is converted to float and the result is float.
  • / always produces a float. 7 / 2 is 3.5. 10 / 2 is 5.0. There is one division operator and it means mathematical division. Floor division is not in Milestone 1; if it proves necessary it gets its own operator and ADR.
  • Integer overflow is a runtime error (E0306), not silent two's-complement wraparound. All int arithmetic uses checked operations internally.
  • % is the remainder with the sign of the dividend; x % 0 is E0305.
  • Equality across types: 1 == 1.0 is true (compared by mathematical value). Ordering likewise.

Consequences

  • int and float are visibly different (type(3) vs type(3.0), str(3) = "3" vs str(3.0) = "3.0"), which matches user expectation for "is this a whole number".
  • / never surprises a beginner with 1/2 == 0. The cost is that a / b on two ints you wanted floored needs int(a / b) (or a future //).
  • Overflow-as-error trades raw speed and C-like wraparound for predictability. A program that overflows i64 is almost always buggy; failing loudly is right for a scripting language. Bignum integers are a possible future ADR.
  • The interpreter's arithmetic path has a 2×2 type match plus checked ops — a little verbose, fully contained in one module.

Alternatives considered

  • Single float64 number type. Simplest implementation, but type() can't distinguish whole numbers, large integers lose precision silently past 2^53, and array indices/loop counters get awkward.
  • / = floor when both ints (Python 2, C). The 1/2 == 0 footgun; Python itself abandoned it.
  • Wrapping overflow. Fast and predictable if you know it happens; a silent correctness trap if you don't. Wrong default for scripting.
  • Arbitrary-precision int by default. No overflow at all, but a performance and implementation cost that M1 does not need; leaves i64 semantics to reintroduce later. Deferred, not rejected.