> For the complete Mojo documentation index, see [llms.txt](/llms.txt).
> Markdown versions of all pages are available by appending .md to any URL (e.g. /docs/manual/basics.md).

# Mojo trait declarations

<!-- Sources:
ParserStmts.cpp (parseTraitStmt, maybeMarkDefaultedTraitMethod,
parseVarStmt trait rejection, parseAliasDeclStmtBody trait
handling), DeclResolution.cpp (resolveSignature(TraitDeclOp),
resolveBody(TraitDeclOp), resolveBody(TraitType),
addParentDeclsToTrait, addSelfTypeToTrait,
resolveSyntheticSignature, parseOptionalInheritanceList,
resolveSignature(AliasDeclOp) trait branch),
DeclResolver.cpp (resolveSignature dispatch, resolveBody
dispatch), Traits.cpp (verifyAndBuildConformance,
signatureResolveDefaultTraitFnStubs,
checkMethodConstraintStatus), Traits.h,
StructEmitter.cpp (synthesizeDefaultTraitMethodWrapper),
ASTDecl.h (traitConformanceLineage, doesNominalTypeConformTo),
TokenKinds.def, ExprNode.h, MojoDiags.h, ParserBase.h
-->

A *trait* defines requirements that a conforming type must satisfy
including methods, associated types, and constants. Traits are similar to
*protocols* in Swift, *interfaces* in Java, and *traits* in Rust. When a
type conforms to a trait, the compiler checks every requirement and rejects
the code if anything is missing.

## Trait declarations

Traits are declared with the `trait` keyword followed by the trait name and
an optional refinement list. The body contains the trait's requirements,
both required and provided:

```text
trait Name:
    body

trait Name(ParentA, ParentB):
    body
```

Traits must be declared at the top level of a file. They
can't be nested inside structs, other traits, or functions:

```mojo
struct Outer:
    trait Inner:  # Error: nested trait not supported here
        ...
```

### Marker traits

Empty traits are called *marker traits* and signal that a type has a
specific property or capability without refining other traits or declaring
requirements:

```mojo
trait AnyType:

    pass
```

Mojo marker traits include: `AnyType`, `TrivialRegisterPassable`,
`RegisterPassable`, and `ImplicitlyCopyable`. They tell the compiler
about a type's properties, supporting compile-time optimizations.

## Trait body elements

A trait body can contain these elements:

<!-- markdownlint-disable MD013 -->

| Element                           | Syntax                  | Role                                     |
|-----------------------------------|-------------------------|------------------------------------------|
| Required method                   | `...` body              | Conforming types must implement          |
| Provided method                   | Code body               | Inherited unless overridden              |
| Comptime member - associated type | `comptime Name: Trait`  | Conforming types provide a concrete type |
| Comptime member - required value  | `comptime name: Type`   | Conforming types provide a value         |
| Comptime member - constant        | `comptime name = value` | Shared across all conforming types       |

<!-- markdownlint-enable MD013 -->

## Trait and member names

<!-- VERIFIED: From ParserStmts.cpp parseTraitStmt() -->

Trait names must be valid identifiers. By convention, they
describe a capability: `Writable`, `Hashable`, `Copyable`.

### Naming conventions

<!-- markdownlint-disable MD013 -->

| Element            | Naming                                                             | Notes                                                                    |
|--------------------|--------------------------------------------------------------------|--------------------------------------------------------------------------|
| Trait name         | `PascalCase`                                                       | Capabilities gained by conformance: `Equatable`, `Copyable`, `PathLike`. |
| Instance method    | `lower_snake_case()`                                               | Method's action: `write_to()`, `update()`                                |
| Static method      | `lower_snake_case()`                                               | Method's action: `get_type_name`, `get_element_bitwidth`                 |
| `comptime` members | Trait compositions are `PascalCase`. Values are `lower_snake_case` | Describes use: `KeyElement`, `element_bitwidth`                          |
| Associated type    | `PascalCase`                                                       | Describes use: `Element`, `Iterator`                                     |

<!-- markdownlint-enable MD013 -->

:::caution
When defining traits, avoid private member names with single or double
underscore prefixes. Required members may be hidden from trait users.
For similar reasons, don't use `@doc_hidden` to hide trait members.

The standard library has a small number of exceptions for required trait
elements known to the compiler.
:::

## Methods

Traits define both required and provided methods, and both instance and
static members. Instance methods take `self` as the first parameter. Static
methods require the `@staticmethod` decorator.

### Required methods

An ellipsis (`...`) marks a required method. Conforming types must provide
an implementation:

```mojo
trait RequiredMethods:
    def required_method(self):
        ...

    @staticmethod
    def required_static_method():
        ...

@fieldwise_init
struct SampleStruct(RequiredMethods):
    def required_method(self):
        print("Required method")

    @staticmethod
    def required_static_method():
        print("Required static method")

def main():
    var s = SampleStruct()
    s.required_method()        # Required method
    SampleStruct.required_static_method() # Required static method
```

### Provided methods

A method with a body other than `...` provides a default implementation.
Conforming types automatically receive that behavior but can also override
it:

```mojo
trait ProvidedMethods:
    def provided_method(self):
        print("Provided method")

    @staticmethod
    def provided_static_method():
        print("Provided static method")

@fieldwise_init
struct SampleStruct(ProvidedMethods):
    def provided_method(self):
        print("Overridden provided method")

def main():
    var sample = SampleStruct()
    sample.provided_method()        # Overridden provided method
    SampleStruct.provided_static_method() # Provided static method
```

Both required and provided methods can return values:

```mojo
trait Describable:
    def provided_describe(self) -> String:
        return "no description"  # Type can override this implementation

    def required_describe(self) -> String:
        ...  # Type must provide an implementation for this method
```

Provided behavior can't use implementation details from any specific
conforming type, as a trait has no knowledge of a type's capabilities
beyond those declared in the trait and refinement list. It must work
across all of them.

### `pass` vs `...`

`pass` and `...` mean distinct things in trait bodies:

- `...` marks a required method stub.
- `pass` is a no-op that counts as a provided implementation
  body. It's only valid when the method returns `None`.

If a method declares a return type but uses `pass` as its body,
the compiler will encourage you to replace it with `...`:

```mojo
trait Unsupported:
    def __compute__(self) -> Int:
        pass
    # Error: trait method has results but default
    # implementation returns no value; did you mean '...'?
```

## Comptime members - associated types

An associated type is a `comptime` member that declares a related
subordinate type that conforming types must specify. For example, an
associated type might be the `Element` type for a container or
collection trait, or the `Key` and `Value` types for a map.

The associated type is declared as a `comptime` member without an
initializer. Only traits can use this declaration form. Conforming structs
provide the concrete value that satisfies any constraints declared in the
trait.

In the following example, `Self` refers to the conforming type, so
`Self.Associated` refers to the conforming type's value for the associated
type `Associated`:

```mojo
trait Boxable:
    comptime Associated: Writable & Copyable & ImplicitlyDestructible

    def unbox(self) -> Self.Associated:
        ...

@fieldwise_init
struct ConcreteBox(Boxable):
    comptime Associated = String
    var value: Self.Associated

    def unbox(self) -> Self.Associated:
        return self.value.copy()

def main():
    var box = ConcreteBox(value="Hello")
    var unboxed = box.unbox()  # Known to be Copyable
    print(unboxed)             # Known to be Writable
    _ = unboxed^               # Known to be ImplicitlyDestructible
```

An associated type can also be assigned from call sites with a generic
parameter. This lets the trait work across a family of types:

```mojo
comptime Base = Copyable & ImplicitlyDestructible & Writable

@fieldwise_init
struct Box[T: Base](https://mojolang.org/docs/reference/Boxable.md):
    comptime Associated = Self.T
    var value: Self.Associated

    def unbox(self) -> Self.Associated:
        return self.value.copy()
```

A `comptime` without an assignment, type, or traits is an error:

```mojo
trait Unsupported:
    comptime X
    # Error: expected '=' after comptime declaration

trait Supported:
    comptime X: Copyable # OK: associated type
    comptime y: Int      # OK: required value
    comptime z = 42      # OK: constant
```

Outside of traits, a `comptime` member without an initializer is an error:

```mojo
struct Unsupported:
    comptime X: Int
    comptime Y: Copyable
    # Error: only traits may contain a comptime member
    # without an initializer
```

## Comptime members - constants and required values

A trait can declare `comptime` constants (shared value) and required
assignments (conforming types must provide a value).

### Constants

This trait provides a usable bitwidth for conforming types based on
the `Element` associated type and a named trait composition:

```mojo
from std.sys.info import bit_width_of

trait Test:
    comptime Element: RegisterPassable
    comptime element_bitwidth = bit_width_of[Self.Element]()

    comptime KeyElement = Copyable & ImplicitlyDestructible & Writable

@fieldwise_init
struct SampleStruct[T: KeyElement](https://mojolang.org/docs/reference/Test.md):
    comptime Element = Int64
    var x: Self.T

    def show_element_bitwidth(self):
        print(Self.element_bitwidth)

def main():
    var s = SampleStruct[Int64](https://mojolang.org/docs/reference/x=42.md)
    s.show_element_bitwidth()  # 64
    print(s.x)                 # 42
```

:::note
Don't use traits to define general-purpose constants like `PI` or
`SPEED_OF_LIGHT`. Define them at the top level of a module for local use,
or as a public member of a related struct for broader use.
:::

## Comptime members: required values

A required value is a `comptime` member without an initializer. Conforming
types must provide a value for it. This is useful when the trait needs a
compile-time constant that varies across conforming types. For example, a
`Measurable` trait might require a `unit` string and an `always_positive`
boolean to validate measurements.

In this example, the trait requires conforming types to provide a
`unit` string, an `always_positive` boolean, and a `get_value()` method.
The `validate()` function uses those requirements to check that the value
is positive when `always_positive` is `True`:

```mojo
trait Measurable:
    comptime unit: StaticString          # Required
    comptime always_positive: Bool       # Required

    def get_value(self) -> Float64: ...  # Required method

def validate[T: Measurable](https://mojolang.org/docs/reference/measurement: T.md) raises:
    comptime if T.always_positive:
        if Float64(measurement.get_value()) < 0.0:
            raise Error(t"{T.unit} cannot be negative")

@fieldwise_init
struct Pascals(Measurable):
    comptime unit: StaticString = "Pa"
    comptime always_positive: Bool = True
    var value: Float64
    def get_value(self) -> Float64:
        return self.value

def main() raises:
    validate(Pascals(value=101325.0))   # Validation succeeds
    # validate(Pascals(value=-101325.0))  # Validation fails
    # run-time error:
    # "Unhandled exception caught during execution: Pa cannot be negative"
```

A similar conformance for `DegreesCentigrade` would set the `unit` to
`"°C"` and `always_positive` to `False`. A value of `-10.0` would pass
validation for `DegreesCentigrade` and fail for `Pascals`.

## Trait refinement

When a trait refines another, its constraint implies the parent's constraint:

```mojo
trait Printable:
    def to_string(self) -> String:
        ...

trait PrettyPrintable(Printable):
    def to_pretty_string(self) -> String:
        ...

@fieldwise_init
struct Box[T: Copyable & Writable & ImplicitlyDestructible](https://mojolang.org/docs/reference/PrettyPrintable.md):
    var value: Self.T

    def to_string(self) -> String:
        return String(t"Box({self.value})")

    def to_pretty_string(self) -> String:
        return String(t"Box with value: {self.value}")

def render[T: PrettyPrintable](https://mojolang.org/docs/reference/item: T.md):
    # to_string() available: PrettyPrintable refines Printable
    print(item.to_string(), "-", item.to_pretty_string())

def main():
    render(Box(1))       # Box(1) - Box with value: 1
    render(Box("hello")) # Box(hello) - Box with value: hello
```

A function requiring `T: PrettyPrintable` can call any method
from `Printable` without naming it in the constraint.

### Constraint resolution order

When the compiler resolves a trait constraint:

- The parameter's declared traits are checked first.
- Parent traits are included transitively.
- If the constraint uses `&`, all composed traits must be
  satisfied.
- If a `where` clause is present, its constraints are checked
  after parameter-level constraints.

If any check fails, the compiler reports which trait the type doesn't
conform to.

A child trait can override a parent method by declaring a method with the
same signature. The parent's version is replaced in the child's
requirements.

:::note
Every trait implicitly refines `AnyType`.
:::

## Trait restrictions

Traits don't support parameter lists:

```mojo
trait Unsupported[T]:  # Error: trait declarations do not support
    ...                # parameters
```

Traits can't declare or use fields:

```mojo
trait Unsupported:
    var x: Int  # Error: traits do not support 'var' fields
```

Traits don't support `where` clauses on methods:

```mojo
trait Unsupported:
    def maybe(self) -> Int where Self: Sized:
        ...
    # Error: 'where' clauses on trait methods are not supported
```

## Conformance checks

The compiler checks every requirement and errors on unmet ones.

### Missing methods

```mojo
trait Sized:
    def __len__(self) -> Int: ...

@fieldwise_init
struct SizedStruct[T: Copyable](https://mojolang.org/docs/reference/Sized.md):
    var backing_store: List[Self.T]

# Error: 'SizedStruct[T]' does not implement all requirements
# for 'Sized'
# Note: required function '__len__' is not implemented
```

### Missing required members

```mojo
trait Container:
    comptime Element: Copyable

@fieldwise_init
struct Bag(Container):
    var data: Int
    # Error: 'Bag' does not implement all requirements for
    # 'Container'
    # Note: required member 'Element' is not specified
```

### Type mismatch on associated types

```mojo
trait Taggable:
    comptime Tag: Sized

@fieldwise_init
struct Widget(Taggable):
    comptime Tag = Int
    # Note: comptime member 'Tag' type Int does not conform
    # to trait's required type Sized
```

### Provided method conflicts

When two traits in a struct's conformance list produce
conflicting provided methods for the same method, the struct must
implement it manually:

```mojo
trait Greeter:
    def greet(self):
        print("Hello from Greeter")

trait Welcomer:
    def greet(self):
        print("Welcome from Welcomer")

@fieldwise_init
struct Host(Greeter, Welcomer):
    pass
    # Error: trait method requirement greet has conflicting
    # default implementations in Greeter and Welcomer; you
    # must implement it manually
```
