Declaration derives#
@derive generates a closed set of checked members on a record. It is a declaration-augmentation phase, not a text macro: it cannot add imports, top-level declarations, modules, or independently nameable types.
The four built-in providers are:
| Provider | Generated surface |
|---|---|
Debug |
debug(self): string and nupp.Debug conformance |
Default |
static default(): T and nupp.default(T) support |
From |
static from(value): T and nupp.into(value, T) support |
JSON |
toJSON, static fromJSON, fieldCodec, and nupp.data.JSONEncodable conformance |
Generated members participate in normal member lookup, generic inference, and interface checking. A written member of the same name is a compile-time conflict. Stacked @derive applications combine, but a provider cannot be requested twice.
Debug#
Debug output follows declaration order. Strings are quoted, map keys are sorted, and recursive runtime tables render as <cycle>. Field annotations may hide or redact values:
Default#
Optionals default to nil; booleans to false; numerics to zero; strings to an empty string; and arrays and maps to fresh empty tables. Tuples and finite shapes default member by member. A nominal field uses its own derived default(). @default(value) supplies a literal compile-time value and mutable literal tables are copied for every call.
Required recursive default graphs are rejected. Make the recursive edge optional or give it an explicit terminating default.
From#
From is deliberately the unambiguous newtype conversion. Its record must have exactly one stored field and no written constructor. It does not perform structural record conversion or validation; fallible conversions remain ordinary functions.
JSON#
JSON encoding is direct and deterministic: record and shape fields use declaration order, string map keys are sorted by byte order, strings must be valid UTF-8, and cycles or nesting beyond 128 containers fail with a JSON path. Encoding does not use or mutate cjson settings.
Decoding uses a private nupp.data.newJSON() configured with array metatables disabled, depth 128, and invalid numbers disabled. Generated validation checks the raw value before returning the record. Mutating nupp.data or another JSON instance cannot alter a derived codec.
Record options:
@json(unknown = "reject"), the default, rejects unknown keys.@json(unknown = "ignore")ignores unknown keys.
Field options:
name = "wire_name"renames the key.omit = trueremoves the field in both directions and requires a default.omitEmpty = trueomits nil, false, empty strings, and empty tables only while encoding.
Supported schemas include booleans, strings, finite numbers, exactly representable integer widths, optionals, arrays, tuples, string-keyed maps, finite shapes, and records deriving JSON. int64 and uint64 are rejected because JSON numbers cannot exactly round-trip their full range. The erased integer type is checked against the safe interval at runtime.
fromJSON returns T?, string?. Errors name the failing path, for example $.user_id: expected integer in range or $: unknown field "user_nmae".
Relationship to comptime#
Comptime evaluates closed value-producing programs after normal type checking. Derives run as part of declaration checking and may attach only their compiler-owned member recipes. They can share reflection and materialization infrastructure, but neither turns comptime into arbitrary source generation.