On this page
article
Chapter 10: Interfaces
Defining an Interface
interface Animal {
fn name(*const self): []const u8;
fn sound(*const self): []const u8;
fn legs(*const self): u32;
}
Implementing an Interface
type Dog = struct {
name_: []const u8,
};
type Cat = struct {
name_: []const u8,
};
provide Animal for Dog {
fn name(*const self): []const u8 { return self.name_; }
fn sound(*const self): []const u8 { return "woof"; }
fn legs(*const self): u32 { return 4; }
}
provide Animal for Cat {
fn name(*const self): []const u8 { return self.name_; }
fn sound(*const self): []const u8 { return "meow"; }
fn legs(*const self): u32 { return 4; }
}
Static Dispatch — Generics
fn describe[A: Animal](animal: *const A) {
debug.print("{} says {} and has {} legs\n",
.{animal.name(), animal.sound(), animal.legs()});
}
var dog = Dog { .name_ = "Rex" };
var cat = Cat { .name_ = "Whiskers" };
describe(&dog); -- monomorphized for Dog
describe(&cat); -- monomorphized for Cat
Dynamic Dispatch — dyn
When you need a collection of different types:
dyn interface Animal {
fn name(*const self): []const u8;
fn sound(*const self): []const u8;
}
fn describeAll(animals: [](*dyn Animal)) {
for a in animals {
debug.print("{} says {}\n", .{a.*.name(), a.*.sound()});
}
}
var dog = Dog { .name_ = "Rex" };
var cat = Cat { .name_ = "Whiskers" };
var animals = []*dyn Animal{ &dog, &cat };
describeAll(&animals);
Interface Requirements
Interfaces can require other interfaces:
interface Printable {
fn print(*const self, writer: *Writer): !void;
}
interface Saveable requires Printable {
fn save(*const self, path: []const u8): !void;
}
-- Saveable: must implement both Printable and Saveable
Operator Overloading
operator (+) = Add;
operator (*) = Mul;
operator (=) = Eq;
interface Add[T] {
fn add(a: T, b: T): T;
}
type Vec2 = struct { x: f32, y: f32 };
provide Add[Vec2] for Vec2 {
fn add(a: Vec2, b: Vec2): Vec2 {
return .{ .x = a.x + b.x, .y = a.y + b.y };
}
}
var a = Vec2 { .x = 1.0, .y = 2.0 };
var b = Vec2 { .x = 3.0, .y = 4.0 };
var c = a + b; -- Vec2 { .x = 4.0, .y = 6.0 }
The Index Interface
-- arr[i] desugars to arr.getIndex(i)?
-- unsafe { arr.getIndexUnchecked(i) } for unchecked access
provide Index for MyArray {
type Value = i32;
type Idx = usize;
fn getIndex(*const self, i: usize): !*const i32 {
if i >= self.len { return error.OutOfBounds; }
unsafe { return self.getIndexUnchecked(i); }
}
unsafe fn getIndexUnchecked(*const self, i: usize): *const i32 {
unsafe { return #ptrAdd(self.ptr, i); }
}
fn setIndex(*self, i: usize, val: i32): !void {
if i >= self.len { return error.OutOfBounds; }
unsafe { self.setIndexUnchecked(i, val); }
}
unsafe fn setIndexUnchecked(*self, i: usize, val: i32): void {
unsafe { #ptrAdd(self.ptr, i).* := val; }
}
}