Traits
Traits define behavioral contracts that types can implement. They work with for blocks to ensure types provide specific functionality.
Defining a Trait
Section titled “Defining a Trait”A trait declares method signatures that implementing types must provide:
trait Display { fn display(self) -> string}Implementing a Trait
Section titled “Implementing a Trait”Use for Type: Trait to implement a trait for a type:
type User { name: string, age: number }
for User: Display { fn display(self) -> string { `${self.name} (${self.age})` }}The compiler checks that all required methods are implemented. If you forget one, you get a clear error:
Error: trait `Display` requires method `display` but it is not implemented for `User`Default Implementations
Section titled “Default Implementations”Traits can provide default method bodies. Implementors inherit them unless they override:
trait Eq { fn eq(self, other: string) -> boolean fn neq(self, other: string) -> boolean { !(self |> eq(other)) }}
for User: Eq { fn eq(self, other: string) -> boolean { self.name == other } // neq is inherited from the default implementation}Multiple Traits
Section titled “Multiple Traits”A type can implement multiple traits:
for User: Display { fn display(self) -> string { self.name }}
for User: Eq { fn eq(self, other: string) -> boolean { self.name == other }}Codegen
Section titled “Codegen”Traits are erased at compile time. for User: Display compiles to exactly the same TypeScript as for User — the trait just tells the checker that a contract is satisfied.
// Floefor User: Display { fn display(self) -> string { self.name }}
// Compiled TypeScript (identical to plain for-block)function display(self: User): string { return self.name; }Deriving Traits
Section titled “Deriving Traits”Record types can auto-derive trait implementations with deriving. This generates the same code as a handwritten for block with no runtime cost:
type User { id: string, name: string, email: string,} deriving (Display)This generates:
display(self) -> string- string representation likeUser(id: abc, name: Ryan, email: r@t.com)
Derivable traits
Section titled “Derivable traits”| Trait | Generated implementation |
|---|---|
Display | TypeName(field1: val1, field2: val2) format |
Compiled output
Section titled “Compiled output”type User { name: string, age: number } deriving (Display)// Generated TypeScripttype User = { name: string; age: number };
function display(self: User): string { return `User(name: ${self.name}, age: ${self.age})`;}Deriving rules
Section titled “Deriving rules”derivingonly works on record types (not unions)- A handwritten
forblock overrides a derived implementation - Only
Displayis derivable —Eqis built-in via==
- All required methods (those without default bodies) must be implemented
- Default methods are inherited unless overridden
- Traits are compile-time only - no runtime representation
- No orphan rules - scoping via imports handles conflicts
- No trait objects or dynamic dispatch - traits are a static checking tool