Skip to content

Traits

Declare static behavior contracts, bounds, defaults, supertraits, and associated items.

Updated View as Markdown

A trait names behavior that types can implement.

trait Summary {
    fn summary(self): string
}

Trait names use PascalCase; methods use snake_case.

Requirements

A method without a body is required.

trait Shape {
    fn area(self): float
    fn perimeter(self): float
}

self denotes a receiver. mut self permits a method contract that updates through the receiver.

Static requirements omit self.

trait Parse[T] {
    fn parse(input: string): T
}

Self

Self names the implementing type.

trait Merge {
    fn merge(self, other: Self): Self
}

This allows a requirement to relate inputs and outputs to the implementation target without introducing another type parameter.

Generics

Traits can declare type parameters.

trait Convert[T] {
    fn convert(self): T
}

A generic function can require a trait with concrete or parameterized arguments.

fn convert_all[A, B](values: []A): []B
where A: Convert[B] {
    return values.map { value => value.convert() }
}

Bounds

Use a where clause to state requirements on type parameters.

fn show[T](value: T): string
where T: Summary + Clone {
    return value.summary()
}

The checker makes only the bounded methods and operations available in the generic body. A later implementation cannot retroactively justify an unbounded call.

Supertraits

Place parent requirements after :.

trait Named: Summary {
    fn name(self): string
}

Implementing Named requires its Summary contract as well. Multiple supertraits use +.

Supertrait cycles are rejected.

Defaults

A method body in a trait is a default implementation.

trait Named: Summary {
    fn name(self): string

    fn label(self): string {
        return "${self.name()}: ${self.summary()}"
    }
}

An implementation inherits label unless it supplies an override. The default body is still checked against the trait’s generic Self and bounds.

Associated types

An associated type lets an implementation choose a type tied to itself.

trait Source {
    type Item
    fn next(mut self): Option[Item]
}

Implementations bind the associated type before methods using it are checked.

Associated types are useful when one implementation has one natural item type and making every call repeat that type parameter would be noisy.

Associated constants

Traits can declare associated constants and implementations can provide their values.

The declaration and binding forms are implemented, while the general application-facing lookup spelling is still being stabilized. Avoid exposing associated-constant access as a public dependency until its specification is final.

Sealing

@sealed restricts implementations to the trait’s declaring file.

@sealed
trait InternalNode {
    fn lower(self): int
}

Use sealing when exhaustive compiler knowledge or representation safety depends on controlling every implementation.

Opaque use

impl Trait accepts or returns a concrete value through a trait-only interface.

fn area(shape: impl Shape): float {
    return shape.area()
}

This is statically dispatched. It is not a dynamically typed trait object.

Core traits

The prelude defines contracts including:

  • Equatable, Hashable, and Comparable[T];
  • Display and Debug;
  • Numeric, Neg, Not, and bitwise operator traits;
  • Default, Clone, From[T], and Into[T];
  • Iterator[T] and Iterable[T];
  • Bytes, Buffer, Drop, and Selectable[T].

Their methods and laws are documented in Traits.

Dispatch

Trait dispatch is static. Generic calls are specialized for reachable concrete types, and the compiler records the implementation selected for each call.

Atoll currently has no dyn Trait spelling, runtime vtable contract, or downcast operator. Use enums or anonymous unions when runtime alternatives must remain explicit.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close