struct
Capy
struct Name { field : type, ... }A struct is a named, fixed layout of typed fields. The compiler checks its shape. A missing or misspelled field is a compile error.
Declare one at the top level of a unit, then construct it by passing the fields in order:
struct Point { x : s32, y : s32 }
function RENDER(request : dval) {
var origin := Point(0, 0)
print(origin.x, ",", origin.y, "\n")
}Fields are mutable, the binding is shared
Reading and writing fields uses .:
struct Counter { total : s32 }
function bump(counter : Counter) {
counter.total = counter.total + 1
}
function RENDER(request : dval) {
var counter := Counter(0)
bump(counter)
bump(counter)
print(counter.total, "\n")
}A struct passed to a function shares identity with the caller's value. A function that writes a field changes what the caller sees. A dval crossing a unit boundary is copied instead.
Static type and field reflection
Struct values support three reflection expressions:
| Expression | Static result | Meaning |
|---|---|---|
value::type_name | string | The declared struct name after alias resolution. |
value::size | s64 | The number of declared fields. This is not a byte size. |
value::items | dval | A map that describes the current field values. |
value::items evaluates value once. It creates a snapshot and does not change the struct. Changes to the returned map do not change the struct.
The map uses each field name as a key. Each field entry has this shape:
{
value: reflected_field_value,
type_name: "resolved field type"
}Use fields.name.value for a fixed field name. Use fields[key]["value"] when the field name comes from a value. Do not depend on map iteration to preserve declaration order.
Reflection converts fields as follows:
| Struct field | Reflected value |
|---|---|
Numeric scalar or bool | A scalar dval. Use the field type constructor to recover the static type. |
string | A string dval. |
dval | A copied dynamic value. |
| Struct | A nested field map with the same entry shape. |
| Typed array | A dval list. Each item uses the array item conversion. |
| Function value | A current-workspace callable with the exact function type. |
Wide integers retain their exact value. The returned dval owns its callable references. A callable extracted into a typed local remains owned by that local. Serialization replaces callable values with none, as it does for other DValue callables.
The compiler rejects value::size and value::items when the receiver is not a struct. value::type_name works on all value types. The types guide defines its canonical names and explains parameter::type.
Choosing between a struct and a dval
Use a struct when the source defines the shape and the compiler must check it. Use a dval for request input, decoded data, database rows, and unit boundaries.
A single-field struct also acts as a constructor for its field type. For example, struct Meters { value : f64 } lets Meters accept an f64.
Exporting a struct
#exports publishes a struct's layout so another unit can name it after #import:
#exports Shape
struct Shape { value : s32 }
function RENDER(request : dval) {
print(Shape(3).value, "\n")
}Example
Capy
struct Job {
id : u64
state : string
}
function RENDER(request : dval) {
var job := Job(u64(18446744073709551615), "queued")
var fields := job::items
print(u64(fields.id.value), " ", string(fields.state.value), "\n")
}