Value Representation
Overview
Every value in ƿit is carried in one build-selected word called a PitValue.
The physical encoding is part of a named runtime ABI profile, rather than a
language guarantee:
| Runtime profile | PitValue | Numeric representation | Object references |
|---|---|---|---|
host-nan64-v1 (default) | 64 bits | Tagged integers and short doubles | Tagged host pointers |
playdate-nan32-v1 | 32 bits | Signed-22 integers and finite IEEE-754 binary32 | Bounded region-relative references |
Both profiles use immediate encodings for common values to avoid heap allocation. C code must use the public value and object APIs instead of depending on either physical layout.
Default Host Tag Encoding
The following sections describe host-nan64-v1. The lowest bits of its
64-bit PitValue determine the representation:
| LSB Pattern | Type | Payload |
|---|---|---|
xxxxxxx0 | Integer | 32-bit signed integer in upper bits |
xxxxx001 | Pointer | 61-bit aligned heap pointer |
xxxxx101 | Short float | 8-bit exponent + 52-bit mantissa |
xxxxx011 | Special | 5-bit tag selects subtype |
Integers
If the least significant bit is 0, the value is an immediate 32-bit signed integer. The integer is stored in the upper bits, extracted via v >> 1.
[integer: 32 bits][0]
Range: -2147483648 to 2147483647. Numbers outside this range are stored as short floats or heap-allocated.
Pointers
If the lowest 3 bits are 001, the value is a pointer to a heap object. The pointer is 8-byte aligned, so the low 3 bits are available for the tag. The actual address is extracted by clearing the low 3 bits.
[pointer: 61 bits][001]
All heap objects (arrays, records, blobs, text, functions, etc.) are referenced through pointer-tagged PitValues.
Short Floats
If the lowest 3 bits are 101, the value encodes a floating-point number directly. The format uses an 8-bit exponent (bias 127) and 52-bit mantissa, similar to IEEE 754 but with reduced range.
[sign: 1][exponent: 8][mantissa: 52][101]
Range: approximately ±3.4 * 10^38. Numbers outside this range fall back to null. Zero is always positive zero.
Specials
If the lowest 2 bits are 11, the next 3 bits select a special type:
| 5-bit Tag | Value |
|---|---|
00011 | Boolean (true/false in upper bits) |
00111 | Null |
01011 | Immediate string |
01111 | Exception marker |
Immediate Strings
Short ASCII strings (up to 7 characters) are packed directly into the PitValue without heap allocation:
[char6][char5][char4][char3][char2][char1][char0][length: 3][01011]
Each character occupies 8 bits. The length (0-7) is stored in bits 5-7. Only ASCII characters (0-127) qualify — any non-ASCII character forces heap allocation.
var s = "hello" // 5 chars, fits in immediate string
var t = "" // immediate (length 0)
var u = "longtext" // 8 chars, heap-allocated
Compact Playdate Encoding
playdate-nan32-v1 reserves four exponent-255 binary32 banks for signed-22
integers, object references, the empty text, and special values. Every finite
binary32 word remains an immediate number. A reference payload is a 2-bit
region select plus a 20-bit aligned offset: four bounded 8 MiB windows
(dynamic, ram-static, and up to two mounted read-only images) drawn from the
process-wide region table; references are not truncated C pointers.
Text is a pointer under this profile. The empty text has no body to point at,
so it is a distinguished tag constant of its own bank, exactly as null is —
it indexes nothing, and there is no registry behind it. Opaque native pointers
use a runtime handle API and never occupy a PitValue. The profile also uses
32-bit object headers.
See Actors and Memory for how the profiles relate to the shared stone pools and per-actor heaps.
Null
Null is encoded as a special-tagged value with tag 00111. Null is how ƿit represents absence.
var x = null // special tag null
var y = 1 / 0 // also null (division by zero)
var z = {}.missing // null (missing field)
Boolean
True and false are encoded as specials with tag 00011, distinguished by a bit in the upper payload.
Summary
The exact tag and object layouts are profile-specific. The common contract is that small numbers, booleans, null, and short immediate text values do not require heap allocation. This reduces GC pressure while allowing compact targets to use a genuinely smaller value and object ABI.