conformance: document narrow-int unification (byte/short/int -> Long)

jolt unifies every integer as one exact-integer type, so (byte/short/int n)
report Long not Byte/Short/Integer and instance? Byte is false. Confirmed
substrate-inherent: (byte 5) is a Chez immediate identical? to 5 (nothing to
tag, numbers carry no metadata), and arithmetic compiles to a raw Chez + that a
boxed narrow type would crash. Value/arithmetic/equality are correct.

Certify the value-correctness (= to plain int, arithmetic promotes, is a Number)
and pin the class/instance? divergence under a new :integer-box-model category.
Data/doc only.
This commit is contained in:
Yogthos 2026-06-28 10:28:10 -04:00
parent 59cfa5f53f
commit 4a72897dfd
3 changed files with 37 additions and 2 deletions

View file

@ -2751,6 +2751,21 @@
{:suite "chunking-model / unchunked realization granularity" :label "nth 0 over a vector realizes one" :expected "1" :actual "(let [a (atom 0)] (nth (map (fn [x] (swap! a inc) x) (vec (range 100))) 0) @a)"}
{:suite "chunking-model / unchunked realization granularity" :label "mapcat is fully lazy at construction" :expected "0" :actual "(let [a (atom 0)] (mapcat (fn [x] (swap! a inc) [x]) (range 5)) @a)"}
{:suite "chunking-model / unchunked realization granularity" :label "dedupe is fully lazy at construction" :expected "0" :actual "(let [a (atom 0)] (dedupe (map (fn [x] (swap! a inc) x) (range 5))) @a)"}
;; --- integer-box-model: narrow int values behave as integers (certified) ---
;; jolt unifies every integer as one exact-integer type, so (byte/short/int n)
;; produce value-correct integers — only the reified class differs (below).
{:suite "integer-box-model / narrow ints behave as integers" :label "byte = plain integer by value" :expected "true" :actual "(= (byte 5) 5)"}
{:suite "integer-box-model / narrow ints behave as integers" :label "byte arithmetic promotes" :expected "6" :actual "(+ (byte 5) 1)"}
{:suite "integer-box-model / narrow ints behave as integers" :label "byte is a Number" :expected "true" :actual "(instance? Number (byte 5))"}
;; --- integer-box-model divergences (allowlisted): no narrow box types. A Chez
;; fixnum is an immediate identical to the plain integer (cannot be tagged), so
;; (byte/short/int n) report Long, not Byte/Short/Integer. Value is correct.
;; jolt-k9sw (accepted divergence).
{:suite "integer-box-model / narrow int class collapses to Long" :label "byte class" :expected "java.lang.Long" :actual "(class (byte 5))"}
{:suite "integer-box-model / narrow int class collapses to Long" :label "short class" :expected "java.lang.Long" :actual "(class (short 5))"}
{:suite "integer-box-model / narrow int class collapses to Long" :label "int class" :expected "java.lang.Long" :actual "(class (int 5))"}
{:suite "integer-box-model / narrow int class collapses to Long" :label "instance? Byte is false" :expected "false" :actual "(instance? Byte (byte 5))"}
{:suite "integer-box-model / narrow int class collapses to Long" :label "instance? Long is true" :expected "true" :actual "(instance? Long (byte 5))"}
{:suite "untested / JVM-shape stubs (documented jolt behavior)" :label "class number" :expected "java.lang.Long" :actual "(class 1)"}
{:suite "untested / JVM-shape stubs (documented jolt behavior)" :label "class string" :expected "java.lang.String" :actual "(class \"s\")"}
{:suite "untested / JVM-shape stubs (documented jolt behavior)" :label "class keyword" :expected "clojure.lang.Keyword" :actual "(class :k)"}

View file

@ -119,6 +119,19 @@ allowlisted in `known-divergences.edn`:
chunk. Strictly finer-grained laziness, decided after the chunk fast path
(jolt-j9dz) was made O(n).
## Narrow integer types
jolt unifies every integer as one exact-integer type (`:integer-box-model`,
jolt-k9sw). `(byte n)`/`(short n)`/`(int n)` produce value-correct integers —
arithmetic, `=`, and `hash` behave exactly as the JVM — but report `Long`, not
`Byte`/`Short`/`Integer`, so `(class (byte 5))` and `(instance? Byte (byte 5))`
diverge. This is substrate-inherent: a Chez fixnum is an immediate `identical?`
to the plain integer (nothing to tag, and numbers carry no metadata), so the only
faithful representation is a boxed type — which would crash raw compiled `(+ …)`
(arithmetic emits a bare Chez `+`) or force every `+`/`-`/`*` through an
unwrapping dispatcher, de-optimizing all arithmetic. Same shape as the accepted
BigInt-vs-Long unification.
## Hosting jolt on a new runtime
1. Implement the reader + analyzer + a backend for your runtime (see the Chez port

View file

@ -16,7 +16,9 @@
:seq-type-model
"jolt models every seq as PersistentList (eager) or LazySeq (deferred); JVM reifies a specialized class per producer (Cons/Iterate/LongRange/Repeat/Cycle/ChunkedSeq/StringSeq/KeySeq/RSeq/ArraySeq/SubVector). Values and laziness are correct, only (class …) differs. jolt-aei7",
:chunking-model
"jolt seqs are unchunked: forcing one element realizes one (JVM realizes a ~32-element chunk), and mapcat/dedupe realize 0 at construction where JVM forces the first chunk — jolt is a finer-grained lazy superset. jolt-mm6v"},
"jolt seqs are unchunked: forcing one element realizes one (JVM realizes a ~32-element chunk), and mapcat/dedupe realize 0 at construction where JVM forces the first chunk — jolt is a finer-grained lazy superset. jolt-mm6v",
:integer-box-model
"jolt unifies every integer as one exact-integer type. A Chez fixnum is an immediate identical to the plain integer (no distinct identity to tag, no metadata on numbers), so (byte/short/int n) report Long, not Byte/Short/Integer. Value/arithmetic/equality are correct; a faithful narrow box would crash raw compiled (+ …) or de-optimize all arithmetic. jolt-k9sw"},
:entries
[{:suite "forms / fn",
:label "no param vector",
@ -54,4 +56,9 @@
{:suite "chunking-model / unchunked realization granularity", :label "first over a vector realizes one, not a chunk", :category :chunking-model}
{:suite "chunking-model / unchunked realization granularity", :label "nth 0 over a vector realizes one", :category :chunking-model}
{:suite "chunking-model / unchunked realization granularity", :label "mapcat is fully lazy at construction", :category :chunking-model}
{:suite "chunking-model / unchunked realization granularity", :label "dedupe is fully lazy at construction", :category :chunking-model}]}
{:suite "chunking-model / unchunked realization granularity", :label "dedupe is fully lazy at construction", :category :chunking-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "byte class", :category :integer-box-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "short class", :category :integer-box-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "int class", :category :integer-box-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "instance? Byte is false", :category :integer-box-model}
{:suite "integer-box-model / narrow int class collapses to Long", :label "instance? Long is true", :category :integer-box-model}]}