Skip to main content
Version: Next (unreleased)

Numbers

xisto has two number types. number is a 64-bit IEEE double, as in JavaScript. int is a whole number held in a 64-bit integer register. Indices, lengths and counters are int; that is where most of the speed comes from.

int and number​

ExpressionTypeValue
const a: int = 7int7
a / 2number3.5, as in JavaScript
a % 2, a * 2, a - 1int
Math.trunc(x), Math.floor(x), Math.round(x)int
a + 1.5numberwith warning XS2103
"n=" + astringwith warning XS2106

An int mixed with a number gives a number, and the compiler says so:

x.ts:9:13: warning[XS2103]: int mixed with number in arithmetic: the result is number
help: declare the type you mean: Number(i) for a number, Math.trunc(x) for an int

A number where an int goes is an error. Convert explicitly:

error[XS8018]: return value of 'fact' must be int, but this is number
help: convert explicitly: Math.trunc(x), Math.floor(x), Math.ceil(x) or Math.round(x)

Literals and inference​

An integer literal takes the type its context asks for. Without a context it is a number, as TypeScript infers. A literal above 2^53−1 is a number and is rounded exactly as Node rounds it (9007199254740993 prints 9007199254740992).

A let without a type, started with an integer literal, is an int when every assignment to it is an integer by its form: i++, i--, i += 1, i = i + k, i = Math.floor(x), i = xs.length, with k itself an int. Anything else leaves it a number:

function b(n: int): int { let t = 0; for (let i = 0; i < n; i++) t += i; return t; } // t is int
function c(n: int): int { let r = 1; for (let i = 2; i <= n; i++) r *= i; return r; } // error: r is number

A product is not an integer by form (it can pass 2^53). Write let r: int = 1 when you mean an int. An inferred int becomes a number by itself where a number goes, so code that compiled keeps compiling.

Range and overflow​

An int holds JavaScript's safe integers, ±(2^53−1), so its results never differ from Node's. Leaving the range is a run-time error, never a silent loss of precision:

runtime error: integer overflow: the result left JavaScript's safe integer range (+-2^53 - 1); use number or bigint
at fact (t5.ts:1:77)

int ** int is checked the same way. Use number when an approximate result is fine, bigint when it must be exact.

Indices are int​

Array indices and length values are int. A number index is refused (XS8082); convert it with Math.trunc. An index out of bounds is a run-time error (catchable), where JavaScript reads undefined.

Bitwise operators​

&, |, ^, ~, <<, >> and >>> accept int and number operands and convert them to 32 bits, as JavaScript does: 1 << 31 is -2147483648, -1 >>> 0 is 4294967295. The result is an int. A compound assignment (h ^= c) needs h declared int (XS8024). A boolean operand is refused (XS8115).

−0​

-0 is kept where the value is seen as a number: Math.round(-0.4), 0 * -1 and const r: int = Math.round(-0.4) print -0, as on Node. It is lost in a reassigned int variable or an int[] element, which print 0.

bigint​

bigint literals (123n) and arithmetic work as on Node: 2n ** 70n, %, typeof x === "bigint".

See also​