Skip to content

07 · Traits

A trait defines a set of method signatures that any type can implement. Traits are the primary polymorphism mechanism in Sigil — they replace virtual dispatch tables in most systems languages while remaining zero-cost. A function that accepts impl Area works with any type that implements Area, resolved at compile time.

traits.cssl
trait Area {
fn area(&self) -> f32;
fn perimeter(&self) -> f32;
}
struct Circle { radius: f32 }
struct Rect { width: f32, height: f32 }
impl Area for Circle {
fn area(&self) -> f32 { 3.14159 * self.radius * self.radius }
fn perimeter(&self) -> f32 { 2.0 * 3.14159 * self.radius }
}
impl Area for Rect {
fn area(&self) -> f32 { self.width * self.height }
fn perimeter(&self) -> f32 { 2.0 * (self.width + self.height) }
}
// Generic over anything that implements Area.
fn print_stats(shape: &impl Area) !io {
println!("area = {:.2}", shape.area());
println!("perimeter = {:.2}", shape.perimeter());
}
fn main() !io {
let c = Circle { radius: 5.0 };
let r = Rect { width: 4.0, height: 6.0 };
println!("-- Circle --");
print_stats(&c);
println!("-- Rect --");
print_stats(&r);
}
-- Circle --
area = 78.54
perimeter = 31.42
-- Rect --
area = 24.00
perimeter = 20.00

impl Area in a parameter position is syntactic sugar for <T: Area>(shape: &T) — the compiler monomorphizes print_stats for each concrete type, so dispatch is a direct call with no vtable. Implementing a trait for a type that doesn’t satisfy all method signatures is a compile error; there is no partial implementation.


Next → 08 · Generics