POLYTONE — the AI-native programming language

Guide

Traits

A trait names a behaviour contract; a type implements it inside its own declaration, and a bounded generic function works for every type that honours it.

cheapest.pt
record Money:
    cents: Int

    with Ord:
        fn lt(self, other: Self) -> Bool = self.cents < other.cents

    with Display:
        fn show(self) -> Text = "${self.cents / 100}.{self.cents % 100}"

fn cheapest[T: Ord + Display](items: List[T], fallback: T) -> Text:
    mut best = fallback
    for x in items:
        if x.lt(best):
            best = x
    return "{best}"

fn main() -> Void:
    let prices = [Money(cents: 350), Money(cents: 120), Money(cents: 990)]
    print(cheapest(prices, prices[0]))
    print(cheapest([9, 3, 7], 9))

A trait declares method signatures ('trait Shape:' with 'fn area(self) -> Float' lines — docs allowed, bodies not), and a type implements it in a 'with Shape:' block after its fields and methods, holding the contract exactly: every signature present, nothing extra, same types. Self in any member signature names the implementing type. An implementation is an ordinary method — r.area() calls it, and dispatch is fully static: the compiler resolves every call at compile time, so a trait costs nothing at runtime.

Bounds live on functions: inside 'fn cheapest[T: Ord + Display]' a T-typed value has exactly the bound's methods, several traits join with '+', and every call site must pass a type that implements them all — the error names the exact fix. Two traits built in and predeclared everywhere: Ord ('fn lt(self, other: Self) -> Bool') from which any sort builds, and Display ('fn show(self) -> Text'), which lets a type choose its own spelling in interpolation — without it, and for containers, the honest structural spelling stands. Int, Float and Text are Ord, those plus Bool are Display, so the same bounded function serves your types and the builtins alike; a pub type's built-in impls even travel across modules — time.Instant sorts and spells out of the box. Equality never needs a trait: == is structural for every value.