Guide
Methods
Records and enums can own their behaviour: methods are declared after the fields or variants, in the same block, and take the receiver as a bare self.
record Rect:
w: Float
h: Float
/// The enclosed area.
fn area(self) -> Float = self.w * self.h
/// A rectangle `k` times the size.
fn scaled(self, k: Float) -> Rect = Rect(w: self.w * k, h: self.h * k)
/// One line describing it.
fn label(self) -> Text = "{self.w}x{self.h} = {self.area()}"
fn main() -> Void:
let r = Rect(w: 3.0, h: 4.0)
print(r.label())
print(r.scaled(2.0).label())The first parameter is always the bare self — never annotated, never omitted. Fields come first, then methods, so a reader meets the shape of a type before its behaviour. One name means one thing: a method may not share a name with a field, and no two methods of one record may share a name. Two different records may of course both have area() — the receiver's type picks it.
Enums declare methods the same way, after their variants — and a method reaches a payload the only way anything does, by matching self. A method declared mut self rewrites its receiver instead of returning something: it returns Void, needs a block body, and the receiver must be a named binding declared mut, exactly like xs.push(v).
enum Status:
Active
Banned(reason: Text)
/// Whether the account may act.
fn allowed(self) -> Bool:
match self:
case Status.Active:
return true
case Status.Banned(reason: _):
return false
record Counter:
total: Int
/// Adds `n` to the running total.
fn bump(mut self, n: Int) -> Void:
self.total = self.total + n
fn main() -> Void:
mut c = Counter(total: 0)
c.bump(5)
print("{c.total} {Status.Active.allowed()}")