number: Decimal that computes #34

Closed
opened 2026-10-05 21:07:12 +00:00 by orion · 10 comments
Collaborator

Context

Decimal is declared and planned; 1.0 cannot promise a declaration that answers "not implemented". Database drivers need it for numeric/DECIMAL/Decimal128. This is the epic; the specification is docs/design/DECIMAL.md (section 14 lists the slices).

Source

Steps (one PR each, in this order; this issue does not carry ready itself)

  • #332 design record DECIMAL.md
  • #334 runtime torb_decimal_*, Rounding, the std surface of std/number, natives Ready
  • #335 literals and constants in the checker, IR and both back ends
  • #336 EncodedValue.Exact, exact JSON/YAML/TOML round trip, decimal-encoding conformance program, statuses and docs from "planned" to "stable"

Done when

  • #336 is merged and main CI is green: Decimal arithmetic, comparison, Show, text conversion and Encode/Decode run in both back ends, compiler/src/backend/c/natives.trb has no planned Decimal entry, conformance programs decimal-arithmetic, decimal-literals, decimal-encoding pass with identical output in VM and native.
  • #34 is closed with the link to the landing commit of #336.

Notes

Seed: none of the steps adds a syntax form or a name the compiler looks up (DECIMAL.md section 10; #336 re-checks with torb ir --statistics .). Database drivers (SqlValue.Numeric, Postgres/MySQL/BSON) are not part of this epic; they belong to the driver issues that use Decimal.

Moved from the planning lists of the docs; the design record stays the specification.

## Context `Decimal` is declared and planned; 1.0 cannot promise a declaration that answers "not implemented". Database drivers need it for `numeric`/`DECIMAL`/`Decimal128`. This is the epic; the specification is [docs/design/DECIMAL.md](https://git.torb.dev/torbscript/language/src/branch/main/docs/design/DECIMAL.md) (section 14 lists the slices). ## Source - [ROADMAP.md, planned natives](https://git.torb.dev/torbscript/language/src/branch/main/docs/ROADMAP.md) - [RELEASE.md 1.0 list](https://git.torb.dev/torbscript/language/src/branch/main/docs/design/RELEASE.md) - [FIRST-PARTY.md gap 12](https://git.torb.dev/torbscript/language/src/branch/main/docs/design/FIRST-PARTY.md) - [ENCODING.md](https://git.torb.dev/torbscript/language/src/branch/main/docs/design/ENCODING.md) ## Steps (one PR each, in this order; this issue does not carry `ready` itself) - [x] #332 design record `DECIMAL.md` - [x] #334 runtime `torb_decimal_*`, `Rounding`, the std surface of `std/number`, natives `Ready` - [x] #335 literals and constants in the checker, IR and both back ends - [ ] #336 `EncodedValue.Exact`, exact JSON/YAML/TOML round trip, `decimal-encoding` conformance program, statuses and docs from "planned" to "stable" ## Done when - [ ] #336 is merged and `main` CI is green: `Decimal` arithmetic, comparison, `Show`, text conversion and `Encode`/`Decode` run in both back ends, `compiler/src/backend/c/natives.trb` has no planned `Decimal` entry, conformance programs `decimal-arithmetic`, `decimal-literals`, `decimal-encoding` pass with identical output in VM and native. - [ ] #34 is closed with the link to the landing commit of #336. ## Notes Seed: none of the steps adds a syntax form or a name the compiler looks up (DECIMAL.md section 10; #336 re-checks with `torb ir --statistics .`). Database drivers (`SqlValue.Numeric`, Postgres/MySQL/BSON) are not part of this epic; they belong to the driver issues that use `Decimal`. _Moved from the planning lists of the docs; the design record stays the specification._
Author
Collaborator

[loop:torbscript] intake: in scope as an issue (author orion, label loop), with an owner question: a computing Decimal is a numeric design choice (precision model, rounding, scale, representation) that must be fixed in a design record first. Large; touches natives, checker and both back ends, probably the seed. To be filed as owner decision in refine. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (owner decision expected)

[loop:torbscript] intake: in scope as an issue (author orion, label loop), with an owner question: a computing `Decimal` is a numeric design choice (precision model, rounding, scale, representation) that must be fixed in a design record first. Large; touches natives, checker and both back ends, probably the seed. To be filed as owner decision in refine. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (owner decision expected)
Author
Collaborator

[loop:torbscript] refine: still queued behind the intake order. next: waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z

[loop:torbscript] refine: still queued behind the intake order. next: waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261012 until 2026-10-12T15:14Z

[loop:torbscript] claim refine by session:loop-torbscript-20261012 until 2026-10-12T15:14Z
Author
Collaborator

[loop:torbscript] decided by the loop: Decimal is a numeric design choice inside the language, not an owner category (no public commitment, cost, product direction or breaking change: the type is declared but has never run). Decisions, to be written into docs/design/DECIMAL.md by #332:

  • Value model: an unscaled integer of arbitrary size with an Int32 scale (value = unscaled / 10^scale), like Java BigDecimal / Python decimal, so postgres numeric, mysql DECIMAL and Decimal128 all fit without loss. Runtime layout: sign, base-10^9 limbs, scale; heap value owned by the runtime (the IR already lays out DecimalNumber as a runtime kind).
  • Exactness: + - * are exact (scale of the sum is the larger scale, of the product the sum of scales). Overflow of the scale (Int32) or of memory panics.
  • Division: an infinite expansion cannot be exact, so / rounds to 34 significant digits (the Decimal128 precision), half-even, and panics on division by zero like Int (PANICS.md); % is the truncated remainder with the sign of the dividend (as for Int). divided(by:, scale:, rounding:) and rounded(scale:, rounding:) take an explicit rounding mode (HalfEven, HalfUp, Down, Up, Floor, Ceiling).
  • Equality: by numeric value (1.0 == 1.00), compare and hash consistent with it (hash of the normalised form). Show keeps the scale (19.90 stays 19.90), no exponent form, -0.00 shows as 0.00.
  • Text: TryFrom<String> reads an optional sign, digits with an optional ., optional e exponent; refuses nan, inf, underscores and whitespace with NumberParseError.
  • Literals keep every written digit and never pass through Float64; conversion from Float is an explicit fallible tryFrom (refuses non-finite), to Float explicit and rounded.
  • Seed: none expected; the compiler does not use Decimal and the natives are already declared (manifest entries change from planned to ready). The implementer re-checks.
  • Split (one PR each, order is the dependency order): #332 design record, #334 runtime and natives, #335 literals/constants in IR and back ends, #336 std surface, Encode/Decode Exact, conformance programs.

#34 stays the umbrella and is closed when #336 lands; it does not carry ready itself.

[loop:torbscript] decided by the loop: `Decimal` is a numeric design choice inside the language, not an owner category (no public commitment, cost, product direction or breaking change: the type is declared but has never run). Decisions, to be written into `docs/design/DECIMAL.md` by #332: - **Value model:** an unscaled integer of arbitrary size with an `Int32` scale (value = unscaled / 10^scale), like Java `BigDecimal` / Python `decimal`, so postgres `numeric`, mysql `DECIMAL` and `Decimal128` all fit without loss. Runtime layout: sign, base-10^9 limbs, scale; heap value owned by the runtime (the IR already lays out `DecimalNumber` as a runtime kind). - **Exactness:** `+ - *` are exact (scale of the sum is the larger scale, of the product the sum of scales). Overflow of the scale (`Int32`) or of memory panics. - **Division:** an infinite expansion cannot be exact, so `/` rounds to 34 significant digits (the `Decimal128` precision), half-even, and panics on division by zero like `Int` (PANICS.md); `%` is the truncated remainder with the sign of the dividend (as for `Int`). `divided(by:, scale:, rounding:)` and `rounded(scale:, rounding:)` take an explicit rounding mode (`HalfEven`, `HalfUp`, `Down`, `Up`, `Floor`, `Ceiling`). - **Equality:** by numeric value (`1.0 == 1.00`), `compare` and `hash` consistent with it (hash of the normalised form). **`Show`** keeps the scale (`19.90` stays `19.90`), no exponent form, `-0.00` shows as `0.00`. - **Text:** `TryFrom<String>` reads an optional sign, digits with an optional `.`, optional `e` exponent; refuses `nan`, `inf`, underscores and whitespace with `NumberParseError`. - **Literals** keep every written digit and never pass through `Float64`; conversion from `Float` is an explicit fallible `tryFrom` (refuses non-finite), to `Float` explicit and rounded. - **Seed:** none expected; the compiler does not use `Decimal` and the natives are already declared (manifest entries change from planned to ready). The implementer re-checks. - **Split (one PR each, order is the dependency order):** #332 design record, #334 runtime and natives, #335 literals/constants in IR and back ends, #336 std surface, `Encode`/`Decode` `Exact`, conformance programs. #34 stays the umbrella and is closed when #336 lands; it does not carry `ready` itself.
Author
Collaborator

[loop:torbscript] refine: split into #332 (ready), #334, #335, #336, all linked and ordered, next: waiting (dependency #332 .. #336; #34 closes with #336). Tokens used by this worker: about 90k.

[loop:torbscript] refine: split into #332 (ready), #334, #335, #336, all linked and ordered, next: waiting (dependency #332 .. #336; #34 closes with #336). Tokens used by this worker: about 90k.
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261028 until 2026-10-28T15:30Z

[loop:torbscript] claim refine by session:loop-torbscript-20261028 until 2026-10-28T15:30Z
Author
Collaborator

[loop:torbscript] decided by the loop: #34 stays the epic and does not carry ready; the work is done up to #335 (merged), so only #336 is left. Checked against main (2026-10-28): the std surface listed in #336 (rounded, divided, scale, normalized, unscaledText, Decimal.of, from/tryFrom conversions, Float64.from(Decimal)), the natives (no Decimal entry Planned any more) and the conformance programs decimal-arithmetic / decimal-literals are in. What really remains is the encoding side (EncodedValue.Exact, exact JSON reading) and the status flips in the docs. #336 is narrowed to exactly that and set ready (one PR, two commits, no new issue needed). Decisions recorded there: Exact after Float; a JSON number token stays Float when printing the parsed Float64 returns the token and becomes Exact otherwise (existing tests keep their shape, a Decimal field never loses digits, no extra Decimal parse for ordinary floats); TOML keeps the string form because the format has no decimal type. No owner decision needed: no public commitment, cost, product direction or published-contract change. Seed: none expected, the compiler finds EncodedValue cases by name, so a new case is additive.

[loop:torbscript] decided by the loop: #34 stays the epic and does not carry `ready`; the work is done up to #335 (merged), so only #336 is left. Checked against `main` (2026-10-28): the std surface listed in #336 (`rounded`, `divided`, `scale`, `normalized`, `unscaledText`, `Decimal.of`, `from`/`tryFrom` conversions, `Float64.from(Decimal)`), the natives (no `Decimal` entry `Planned` any more) and the conformance programs `decimal-arithmetic` / `decimal-literals` are in. What really remains is the encoding side (`EncodedValue.Exact`, exact JSON reading) and the status flips in the docs. #336 is narrowed to exactly that and set `ready` (one PR, two commits, no new issue needed). Decisions recorded there: `Exact` after `Float`; a JSON number token stays `Float` when printing the parsed `Float64` returns the token and becomes `Exact` otherwise (existing tests keep their shape, a `Decimal` field never loses digits, no extra Decimal parse for ordinary floats); TOML keeps the string form because the format has no decimal type. No owner decision needed: no public commitment, cost, product direction or published-contract change. Seed: none expected, the compiler finds `EncodedValue` cases by name, so a new case is additive.
Author
Collaborator

[loop:torbscript] refine: #34 reduced to an epic checklist (#332, #334, #335 done; #336 is the last step), #336 rewritten to the definition of ready and labelled ready; no new issue (duplicate check: only #336 matches), no owner question. Tokens used by this worker: about 150k. next: waiting (epic: #336 is ready for implementation; #34 closes when #336 lands)

[loop:torbscript] refine: #34 reduced to an epic checklist (#332, #334, #335 done; #336 is the last step), #336 rewritten to the definition of ready and labelled `ready`; no new issue (duplicate check: only #336 matches), no owner question. Tokens used by this worker: about 150k. next: waiting (epic: #336 is ready for implementation; #34 closes when #336 lands)
Author
Collaborator

[loop:torbscript] close: #336 is closed (PR #544 landed as 9e774663); closing #34 needs main CI green on a landed commit, and main (b471d025, with the budget fix of PR #556) is still running its push checks. next: waiting (main CI green on b471d025, then close #34)

[loop:torbscript] close: #336 is closed (PR #544 landed as 9e774663); closing #34 needs `main` CI green on a landed commit, and `main` (b471d025, with the budget fix of PR #556) is still running its push checks. next: waiting (main CI green on b471d025, then close #34)
Author
Collaborator

[loop:torbscript] close: main CI is green on 38d3edd4 (38d3edd4ab), which contains the landed work of #336 (PR #544, 9e774663) and the budget fix b471d025. All steps of the epic are done. Closing.

[loop:torbscript] close: main CI is green on 38d3edd4 (https://git.torb.dev/torbscript/language/commit/38d3edd4abc7f56c8476e1f387df16a546a44047), which contains the landed work of #336 (PR #544, 9e774663) and the budget fix b471d025. All steps of the epic are done. Closing.
orion closed this issue 2026-10-28 22:50:44 +00:00
Sign in to join this conversation.
No labels
loop
ready
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#34
No description provided.