Types & objects
Classes
Class Definition
class Point(int x, int y) {
# Class fields
int xCoord = x
int yCoord = y
# Methods
func distanceSquared() int {
return xCoord * xCoord + yCoord * yCoord
}
func move(int dx, int dy) void {
xCoord = xCoord + dx
yCoord = yCoord + dy
}
}Creating Instances
Point p = new Point(10, 20)Accessing Fields and Methods
Parentheses rule (one obvious way): anything that computes — a method, a built-in conversion (x.str(), arr.len()), an extension call — is written with (), even when it takes no arguments. Only a stored field (a class field, a tuple element) is accessed bare. Reading a field with () or calling a method without it is a compile error.
Important: Class fields are read-only from outside the class. To modify fields, you must use class methods.
Point p = new Point(10, 20)
int x = p.xCoord # Reading a field — no parens
# p.xCoord = 15; # ERROR: cannot modify field from outside
p.move(5, 5) # Calling a method — parens (even if it took none)
int d = p.distanceSquared() # A zero-argument method still needs ()Example class with methods for modifying fields:
class Counter() {
int value = 0
# Method to modify field from outside
func increment() void {
value = value + 1
}
func add(int amount) void {
value = value + amount
}
func getValue() int {
return value
}
}
Counter c = new Counter()
int current = c.value # Reading: OK
c.increment() # Modifying through method: OK
# c.value = 10; # Direct modification: ERRORNested Classes
class LinkedList() {
class Item(Item prev, any value) {}
Item start
Item end
int length = 0
func add(any value) void {
end = new Item(end, value)
if (length == 0) {
start = end
}
length = length + 1
}
}Constructor
The class body is executed as a constructor:
class ValueStorage(int h, str b) {
int a = h + 1 # Initialization in constructor
func getValue() int {
return a
}
}Field Mutability
Important: Class fields can only be modified inside class methods. From outside the class, fields are read-only.
class Counter() {
int value = 0
# Method to modify field from outside
func increment() void {
value = value + 1 # Modifying inside method: OK
}
func add(int amount) void {
value = value + amount # Modifying inside method: OK
}
func getValue() int {
return value
}
}
Counter c = new Counter()
int current = c.value # Reading field: OK
c.increment() # Modifying through method: OK
# c.value = 10; # Direct modification from outside: ERRORAnother example:
class Random(int seed) {
int previous = 0
func setSeed(int seed) void {
previous = seed # Modifying field inside method: OK
}
func next() int {
int r = previous * 2
previous = r # Modifying field inside method: OK
return r
}
}
Random r = new Random(10)
int val = r.previous # Reading field: OK
r.setSeed(20) # Modifying through method: OK
# r.previous = 30; # Direct modification from outside: ERROROperator Overloading
Classes can define custom behavior for built-in operators using the operator keyword:
class Vector(int x, int y) {
operator +(Vector other) Vector {
return new Vector(x + other.x, y + other.y)
}
operator [](int index) int {
return if (index == 0) then x else y
}
}
Vector a = new Vector(1, 2)
Vector b = new Vector(3, 4)
Vector sum = a + b # Vector(4, 6)
int first = a[0] # 1For the full list of overloadable operators and detailed usage, see Operator Overloading.
Data classes
The classes above are mutable objects shared by reference. For an immutable value type — compared by value and copied across actor and native boundaries — use a data class instead.
Interfaces
A class can be used through an interface — a contract of method signatures it satisfies by shape, with no base class to extend. A class may also name an interface explicitly after its constructor parameters (class Square(int side) : Shape { ... }) to document intent and get errors at the declaration. A method whose return type is Self keeps the concrete type through a fluent chain.