Methods & Constructors
Methods mutate in place, readonly methods work on a copy,
operators overload C++-style, and constructors are called without
new.
Methods and operators
Instance methods take this as an implicit ref —
m.points[i].normalize() mutates in place, exactly what it looks
like. A readonly method takes this as a flattened
copy instead, which is why it is the only kind callable on a temporary:
make(3, 4).sum() consumes the leaves already on the stack. Writing
this inside a readonly method is a compile error, as
is calling a mutating method on a temporary or through readonly
this. Operators are C++-style members — operator+(a,
b) — taking (left, right) by value, dispatched on the
left operand’s struct; a one-argument operator- is unary
negation. != always derives as the negation of ==
and cannot be declared. Reference classes use the same member syntax —
instance forms dispatch on this (operator[](i),
operator+(other)), static forms take
(left, right), and unchecked operator[] declares
the unchecked() fast path. There is no @operator decorator (upstream’s spelling);
classes may declare operator!= because reference
inequality is otherwise the default.
export struct Vec {
x: f32 = 0;
y: f32 = 0;
scale(s: f32): void { // this is an implicit ref
this.x *= s;
this.y *= s;
}
readonly sum(): f32 { // this is a copy; rvalue receivers work
return this.x + this.y;
}
operator+(a: Vec, b: Vec): Vec {
let r = Vec();
r.x = a.x + b.x;
r.y = a.y + b.y;
return r;
}
operator-(v: Vec): Vec { // one argument: unary negation
let r = Vec();
r.x = -v.x;
r.y = -v.y;
return r;
}
}
export function demo(): f32 {
let v = Vec();
v.x = 3;
v.scale(2); // value-local receiver: spills, mutates v
let w = v + -v; // operator dispatch, by value
return w.sum() + (v + v).sum(); // 0 + 12
}
Constructors
Structs declare C++-style constructors: overloadable, by value, called
without new. A constructor body starts from the
default-initialized value (field initializers applied), mutates
this, and returns it implicitly — bare return exits
early, returning a value is an error. Overloads resolve by arity first, then
exact argument types, then numeric coercibility; anything still plural is an
ambiguity error at the call site.
export struct Color {
r: f32 = 0;
g: f32 = 0;
b: f32 = 0;
a: f32 = 1; // defaults run before every body
constructor(r: f32, g: f32, b: f32) {
this.r = r;
this.g = g;
this.b = b;
}
constructor(gray: f32) {
this.r = gray;
this.g = gray;
this.b = gray;
}
}
export function demo(): f32 {
let c = Color(0.5); // no new: construction is by value
let d = Color(1, 0, 0);
return c.g + d.r + d.a; // 0.5 + 1 + 1
}
new does not apply to structs at all — construction is the
call form, and V() spells the default value whether or not
constructors are declared. Declaring constructors never suppresses the default
(a deliberate divergence from C++): array elements and uninitialized locals
need the default state to exist.