Scripting & runtime · bytes
Handle raw bytes as a first-class value.
bytes is an immutable, shared-backed byte value. It is the language's representation for binary data and interoperates with the FFI byte bridges without ever aliasing mutable native storage.
b := bytes([72, 105])
print(b.size()) // 2
print(b[0]) // 72
print(b.decode("utf-8")) // Hi
Construction
Build bytes from an array of byte integers, or from a string via UTF-8 encoding. Invalid byte values and non-byte inputs raise controlled errors rather than producing a malformed value.
from_array := bytes([1, 2, 3])
from_text := "héllo".encode("utf-8")
Operations
Byte values support size()/length() and empty(), integer indexing (b[i]), slice(start, end?), concatenation with +, equality comparison, truthiness, and strict UTF-8 decode("utf-8"). Out-of-range indexing and invalid UTF-8 decode are controlled errors.
a := bytes([1, 2])
joined := a + bytes([3]) // 3 bytes
print(joined.slice(0, 2).size())
print(a == bytes([1, 2])) // true
Identity and sharing
Bytes are immutable and share their backing storage. Assignment, copy()/deepcopy(), closures, nested aggregates, mutex values, and thread/async transfer all preserve the shared backing while giving each aggregate shell independent identity.
Text and JSON boundaries
Bytes are intentionally not text. Rendering, value/text serialization, and JSON reject bytes; convert explicitly with decode("utf-8"). Checked JSON extraction of byte values is available at the embedding boundary.
Byte I/O
open_bytes(path), the stream/managed-file byte reads (read_bytes(n) / read_all_bytes()), and exact raw byte writes return or accept bytes; existing text I/O is unchanged.
data := open_bytes("./asset.bin")
print(data.size())
FFI bridges
ffi_buffer(bytes) and ffi_snapshot_bytes(buffer) are explicit copying bridges: immutable bytes never alias mutable native storage. ffi_bytes() is unchanged.