Structs & Methods¶
Structs let you define custom data types with named fields and methods.
Defining Structs¶
Creating Instances¶
Two styles — constructor and literal:
Both are equivalent. Literal style is clearer when structs have many fields.
Field Access¶
Field Mutation¶
Methods with impl¶
Attach methods to structs using impl:
impl Point do
define distance(other)
let dx be self.x - other.x
let dy be self.y - other.y
return sqrt(dx * dx + dy * dy)
end
define translate(dx, dy)
return Point(self.x + dx, self.y + dy)
end
define to_text()
return f"({self.x}, {self.y})"
end
end
The self keyword
Inside impl methods, self refers to the instance the method is called on.
Using Methods¶
let a be Point(0, 0)
let b be Point(3, 4)
show a.distance(b) -- 5.0
show a.translate(5, 5).to_text() -- (5, 5)
Multiple Impls¶
You can add methods in separate impl blocks:
struct Color do
r, g, b
end
impl Color do
define hex()
return f"rgb({self.r}, {self.g}, {self.b})"
end
end
impl Color do
define is_dark()
return (self.r + self.g + self.b) / 3 < 128
end
end
let red be Color(255, 0, 0)
show red.hex() -- rgb(255, 0, 0)
show red.is_dark() -- false
Structs in Pipes¶
Structs work naturally with pipes:
struct Record do
name, score
end
let records be [
Record("Alice", 95),
Record("Bob", 82),
Record("Carol", 91)
]
records
|> sort_by(fn(r) -> r.score)
|> reverse
|> map(fn(r) -> f"{r.name}: {r.score}")
|> join(", ")
|> show
-- Alice: 95, Carol: 91, Bob: 82
Real-World Example: Stack¶
struct Stack do
items
end
impl Stack do
define push(value)
push(self.items, value)
return self
end
define pop()
return pop(self.items)
end
define peek()
return self.items[len(self.items) - 1]
end
define is_empty()
return len(self.items) is 0
end
define size()
return len(self.items)
end
end
let stack be Stack { items: [] }
stack.push(1)
stack.push(2)
stack.push(3)
show stack.peek() -- 3
show stack.pop() -- 3
show stack.size() -- 2