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()
{
var origin := Point(0, 0)
print(origin.x, ",", origin.y, "\n")
}Output
0,0Fields 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()
{
var counter := Counter(0)
bump(counter)
bump(counter)
print(counter.total, "\n")
}Output
2A struct passed to a function is the caller's object. A function that writes a field changes what the caller sees. The same holds for an any, including one passed to a component or an exported function.
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 | any | A map that describes the current field values. |
value::items evaluates value once. It builds a new map 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:
struct Label
{
name : string
}
function RENDER()
{
var label := Label("Ada")
var fields := label::items
print(json_encode(fields.name), "\n")
}Output
{"value": "Ada", "type_name": "string"}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 any. Use the field type constructor to recover the static type. |
string | A string any. |
any | A copied dynamic value. |
| Struct | A nested field map with the same entry shape. |
| Typed array | An any list. Each item uses the array item conversion. |
| Function value | A function or closure of the current request with the exact function type. |
Wide integers retain their exact value. The returned any 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.
struct Job
{
id : u64
state : string
}
function RENDER()
{
var job := Job(18446744073709551615, "queued")
var fields := job::items
print(u64(fields.id.value), " ", fields.state.value, "\n")
}
Output
18446744073709551615 queuedChoosing between a struct and a dynamic value
Use a struct when the source defines the shape and the compiler must check it. Use an any 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()
{
print(Shape(3).value, "\n")
}Output
3