A struct is a collection of named fields, similar to a struct in other languages.
Runtime structs are nominal types. Two structs with the same field shape are still different runtime types.
They can implement statically resolved receiver methods by defining a top-level function whose first argument is literally named `this`. `this Type` is immutable, `this ~Type` is mutable, and receiver methods can only be called with `value.method(...)`. User-defined struct methods must be declared in the same file as the struct definition.
Receiver methods are also supported on built-in scalar types (`Int`, `Float`, `Bool`, `String`) and use the same `this` rules. The same-file restriction applies to user-defined struct methods.
Structs can be assigned with default arguments, these can be any constant expression.
Person = |
name String,
age Int,
|
-- Create a new instance of the type
person ~= Person("Alice", 30)
-- Access fields using dot notation
io(person.name) -- "Alice"
io(person.age) -- 30
-- Defining a struct, then defining a method for it
Vector2 = |
x Float = 0,
y Float = 0,
|
reset |this ~Vector2|:
this.x = 0
this.y = 0
;
vec = Vector2(12, 87)
~vec.reset()
Methods in Beanstalk are created using the special `this` receiver parameter.
You define a receiver by making the first parameter literally named `this`.
-- Define a struct
Rectangle = |
width Float,
height Float,
|
-- Define an immutable method for the Rectangle struct
area |this Rectangle|:
return this.width * this.height
;
rect = Rectangle(10, 5)
io(rect.area()) -- 50
`this` is reserved for method receivers. You are limited to one `this` parameter per method, and `method(value, ...)` is not valid syntax for calling receiver methods.
Const-coerced struct values are data-only records. They can be read, but they do not expose runtime methods.