Structs
Define, construct, access, mutate, and transfer nominal struct values in Prismio 0.1.
Last verified
A struct declares named fields and creates a nominal, move-only type. Structs group related values without introducing inheritance, methods, or an object runtime.
struct Point {
x: Int,
y: Int
}
fn main() -> Int {
let point = Point { x: 4, y: 9 }
point.x = point.x + 1
return point.x + point.y
}Declaration syntax
Fields are written as name: Type entries inside braces and separated by commas.
struct Request {
id: U64,
retry_count: Int,
path: String
}The declaration introduces Request into the program's type namespace. Field order contributes to the current compiled layout, but source code should use names rather than assuming offsets. A stable cross-version struct ABI is not promised in 0.1.
Fields may contain scalars, enums, arrays, lists, strings, other structs, and permitted optional types. A directly recursive stored field has no finite layout; model recursive links with an optional reference-shaped struct field, as shown on the optional values page.
Construction
A struct literal names its type and provides field initializers:
let request = Request {
id: 42,
retry_count: 0,
path: "/health"
}Every declared field must receive a compatible value. Initializers are matched by field name, not by an anonymous positional tuple. A misspelled, missing, or unknown field is a compile-time error.
Struct literals are expressions and may be returned, passed to functions, or nested inside another literal. Their ownership behavior follows the destination: an owned move-only field transfers into the new struct.
Nominal identity
Two declarations with identical fields remain different types.
struct ScreenPoint { x: Int, y: Int }
struct MapPoint { x: Int, y: Int }
fn main() -> Int {
let screen = ScreenPoint { x: 1, y: 2 }
let map: MapPoint = screen
return map.x
}The compiler does not perform structural conversion. Write an explicit conversion function that constructs MapPoint if the distinction is intentional.
Field access and assignment
Fields are selected with . and initialized by name in a struct literal. Every declared field must have a compatible initializer. Two structs with the same field shapes remain different types.
Field access reads the declared field type:
let attempts: Int = request.retry_countField assignment requires an assignable value of that field type. Compound assignment on a field is not implemented as a general assignment place; spell the operation explicitly:
request.retry_count = request.retry_count + 1Prismio 0.1 permits field assignment through a struct binding even when that binding was not declared mut; mut is enforced for direct binding reassignment. This distinction is current compiler behavior and may be tightened in a later language version.
An optional struct must be unwrapped before member access. Comparing it with none does not flow-narrow the expression; call expect and access the result.
Ownership
Struct values move when stored into another owned location or passed to sink. Ordinary function parameters borrow them. Methods are attached with an impl block and a type satisfies a bound with impl <Trait> for <Type>. Constructors, field visibility modifiers, and inheritance are not implemented.
struct Ticket { number: Int }
fn number(ticket: Ticket) -> Int {
return ticket.number
}
fn close(sink ticket: Ticket) -> Int {
return ticket.number
}
fn main() -> Int {
let ticket = Ticket { number: 9 }
let observed = number(ticket)
return close(ticket) - observed
}number borrows, so the caller can later pass ticket to the consuming close. After close, the binding is moved.
When a struct contains another move-only value, constructing the outer struct transfers the inner value. Reading a scalar field from a borrowed struct is safe; transferring an owned field out of a borrowed parameter is rejected where it would violate the borrow.
Current limitations
- Methods and associated functions are written in
implblocks, inherent or for a trait, and animplmay be generic. There is no dedicated constructor form: write an associated function that returns the struct. - A field has no visibility of its own;
public,privateandinternalapply to functions and methods, not to types or their fields. See visibility. - Structs may be generic; there are no field defaults. A literal that omits a field is accepted, and the omitted field is zero-initialised — a null pointer, a zero number, or a recursively zeroed inline struct.
- There is no update syntax that copies unspecified fields.
- Layout and cross-version ABI stability are not guaranteed.
- Field assignment through an immutable binding is currently accepted and may be tightened.
Use standalone functions for behavior and keep foreign-facing layouts behind a small FFI layer.