Invisible link to canonical for Microformats

ADR-013 DEC64 as the number type


Status

Accepted

Context

Slug intentionally keeps the primitive type set small and prioritizes values that are easy to reason about, portable, and predictable across platforms and runtimes.

Using IEEE-754 binary floating point as the sole numeric type introduces user-visible surprises for common decimal arithmetic (money, percentages, measurements) and can result in platform-dependent edge cases.

Slug’s design goals favor:

  • explicit semantics over implicit coercions
  • deterministic behavior across interpreters and virtual machines
  • predictable formatting and serialization
  • clear failure modes rather than silent corruption or “weird values”

To support these goals, Slug requires a decimal-based numeric representation with well-defined rounding, overflow, and conversion behavior.

Decision

Slug’s number type is DEC64.

Representation

  • A number represents a decimal value of the form:
coefficient × 10^exponent
  • The coefficient and exponent are bounded and finite.

  • The runtime maintains a canonical (normalized) representation where possible, such that equivalent numeric values compare equal and format consistently.

  • Representation details (bit layout, packing strategy) are explicitly not part of the language contract and may vary between runtimes, provided observable semantics remain consistent.

Numeric operation semantics

  • The arithmetic operators +, -, and * operate in decimal space and must be deterministic.
  • / performs decimal division with defined defaults:

    • Default precision: 16 significant digits
    • Default rounding mode: half-even (banker’s rounding)
  • The standard library provides explicit alternatives for callers that require different precision or rounding behavior.

Error model (no NaN in userland)

  • Slug user code does not observe NaN or Infinity as normal values.
  • Invalid numeric operations raise a RuntimeError, including:

    • division by zero
    • overflow or underflow beyond the representable DEC64 range
    • invalid numeric conversions
    • bitwise operations applied to non-integer values
  • Runtimes may use internal sentinel values to implement numeric operations, but these must never be exposed directly to user code.

Integer-ness and bitwise operations

  • A number is considered an integer if it has no fractional component in canonical form.
  • Bitwise operators (&, |, ^, ~, <<, >>) are only valid on integer values.
  • Applying bitwise operations to non-integers raises a RuntimeError.

Conversions and interop

  • All numeric conversions are explicit and checked:

    • toInt() succeeds only if the value is an exact integer within range.
    • toFloat() is permitted but explicitly lossy.
  • Serialization and parsing:

    • The standard library must support stable decimal string formatting.
    • Canonical formatting must round-trip: parse(format(x)) == x.
    • JSON support may encode numbers either as numeric values or strings; string encoding is recommended when exact round-trip fidelity is required (e.g. money).

Consequences

Positive

  • Predictable decimal arithmetic aligned with human expectations.
  • Deterministic behavior across runtimes and platforms.
  • A smaller, simpler numeric surface area with fewer coercion rules.
  • Clear, explicit failure modes instead of silent numeric corruption.

Negative

  • Numeric performance may be lower than hardware-accelerated binary floating point.
  • Some domains (e.g. scientific simulation, graphics, machine learning) may find DEC64 less suitable.
  • The language must clearly specify rounding, precision, and overflow behavior to avoid ambiguity.

Neutral

  • Slug prioritizes correctness, readability, and predictability over maximum numeric throughput.
  • Alternate numeric representations (e.g. binary floats, big decimals, rationals) remain possible as library types, not language primitives.