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 profilePitValueNumeric representationObject references
host-nan64-v1 (default)64 bitsTagged integers and short doublesTagged host pointers
playdate-nan32-v132 bitsSigned-22 integers and finite IEEE-754 binary32Bounded 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 PatternTypePayload
xxxxxxx0Integer32-bit signed integer in upper bits
xxxxx001Pointer61-bit aligned heap pointer
xxxxx101Short float8-bit exponent + 52-bit mantissa
xxxxx011Special5-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 TagValue
00011Boolean (true/false in upper bits)
00111Null
01011Immediate string
01111Exception 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.