> 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).

# Traits

A *trait* is a set of requirements that a type must implement. You can think of
it as a contract: a type that *conforms* to a trait guarantees that it
implements all of the features of the trait.

Traits are similar to Java *interfaces*, C++ *concepts*, Swift *protocols*, and
Rust *traits*. If you're familiar with any of those features, Mojo traits solve
the same basic problem.

You've probably already seen some traits, like `Copyable` and `Movable`, used in
example code. This section describes how traits work, how to use existing
traits, and how to define your own traits.

## Background

In dynamically-typed languages like Python, you don't need to explicitly declare
that two classes are similar. This is easiest to show by example:

```python title="🐍 Python"
class Duck:
    def quack(self):
        print("Quack.")

class StealthCow:
    def quack(self):
        print("Moo!")

def make_it_quack(maybe_a_duck):
    try:
        maybe_a_duck.quack()
    except:
        print("Not a duck.")

make_it_quack(Duck())
make_it_quack(StealthCow())
```

The `Duck` and `StealthCow` classes aren't related in any way, but they both
define a `quack()` method, so they work the same in the `make_it_quack()`
function. This works because Python uses dynamic dispatch—it identifies the
methods to call at runtime. So `make_it_quack()` doesn't care what types
you're passing it, only the fact that they implement the `quack()` method.

In a statically-typed environment, this approach doesn't work:
Mojo functions require you to
specify the type of each argument. If you wanted to write this example in Mojo
*without* traits, you'd need to write a function overload for each input type.

```mojo title="🔥 Mojo"
@fieldwise_init
struct Duck(Copyable):
    def quack(self):
        print("Quack")

@fieldwise_init
struct StealthCow(Copyable):
    def quack(self):
        print("Moo!")

def make_it_quack(definitely_a_duck: Duck):
    definitely_a_duck.quack()

def make_it_quack(not_a_duck: StealthCow):
    not_a_duck.quack()

make_it_quack(Duck())
make_it_quack(StealthCow())
```

```output
Quack
Moo!
```

This isn't too bad with only two types. But the more types you want to
support, the less practical this approach is.

You might notice that the Mojo versions of `make_it_quack()` don't include the
`try/except` statement. We don't need it because Mojo's static type checking
ensures that you can only pass instances of `Duck` or `StealthCow` into the
`make_it_quack()` function.

## Using traits

Traits solve this problem by letting you define a shared set of *behaviors* that
types can implement. Then you can write a function that depends on the trait,
rather than individual types. As an example, let's update the `make_it_quack()`
example using traits. This will involve three steps:

1. Defining a new `Quackable` trait.
2. Adding the trait to the `Duck` and `StealthCow` structs.
3. Updating the `make_it_quack()` function to depend on the trait.

### Defining a trait

The first step is defining a trait that requires a `quack()` method:

```mojo
trait Quackable:
    def quack(self):
        ...
```

A trait looks a lot like a struct, except it's introduced by the `trait`
keyword. Note that the `quack()` method signature is followed by three dots
(`...`). This indicates it isn't implemented within the trait. In this
example, `quack` is a *required method* and must be implemented by
any conforming struct.

A trait can supply a default implementation, so conforming structs
don't need to implement the method themselves. You can provide a full
implementation or use the `pass` keyword. Using `pass` creates a
no-op method that does nothing. In your conforming struct, you
can choose to override this default implementation:

```mojo
trait Quackable:
    def quack(self):
        pass
```

For more information, see
[Default method implementations](#default-method-implementations).

A trait can also include `comptime` members. These are compile-time
constant values. You can define them directly in the trait or require
conforming structs to define them.

A required value is a `comptime` member without an initializer. Conforming
types must provide a value for it. Use required values when each conforming
type needs its own compile-time constant. This lets trait methods adapt
accordingly.

Associated types are a common use for required `comptime`
members. An associated type is a subordinate type used by the trait,
most often in collections and generic data structures.

Provided values can include constants, trait compositions, or types.
You define them once in the trait, and every conforming type has
access to them.

Use required and provided `comptime` members to describe generic
families of types.

For more information, see [`comptime` members for
generics](#comptime-members-for-generics).

### Adding traits to structs

Next, we need some structs that conform to the `Quackable` trait. Since the
`Duck` and `StealthCow` structs above already implement the `quack()` method,
all we need to do is add the `Quackable` trait to the traits it conforms to
(in parenthesis, after the struct name).

(If you're familiar with Python, this looks just like Python's inheritance
syntax.)

```mojo
@fieldwise_init
struct Duck(Copyable, Quackable):
    def quack(self):
        print("Quack")

@fieldwise_init
struct StealthCow(Copyable, Quackable):
    def quack(self):
        print("Moo!")
```

The struct needs to implement any methods that are declared in the trait. The
compiler enforces conformance: if a struct says it conforms to a trait, it must
implement everything required by the trait, or the code won't compile.

### Using a trait as a type constraint

Finally, you can define a function that takes a `Quackable` like this:

```mojo
def make_it_quack[DuckType: Quackable](https://mojolang.org/docs/manual/maybe_a_duck: DuckType.md):
    maybe_a_duck.quack()
```

Or using the shorthand form:

```mojo
def make_it_quack2(maybe_a_duck: Some[Quackable]):
    maybe_a_duck.quack()
```

This syntax may look a little unfamiliar if you haven't dealt with Mojo
[parameters](/docs/manual/parameters/) before. What the first signature
means is that `maybe_a_duck` is an argument of type `DuckType`, where
`DuckType` is a type that must conform to the `Quackable` trait.

The `Some[Quackable]` form expresses the same idea: the type of `maybe_a_duck`
is some concrete type that conforms to the trait `Quackable`.

Both forms work the same, except that the first form explicitly names the type
value. This can be useful, for example, if you want to take two values of the
same type:

```mojo
def take_two_quackers[DuckType: Quackable](https://mojolang.org/docs/manual/quacker1: DuckType, quacker2: DuckType.md):
    pass
```

### Putting it all together

Using the function is simple enough:

```mojo
make_it_quack(Duck())
make_it_quack(StealthCow())
```

```output
Quack
Moo!
```

Note that you don't need the square brackets when you call `make_it_quack()`:
the compiler infers the type of the argument, and ensures the type has the
required trait.

One limitation of traits is that you can't add traits to existing types. For
example, if you define a new `Numeric` trait, you can't add it to the standard
library `Float64` and `Int` types. However, the standard library already
includes quite a few traits, and we'll be adding more over time.

### Traits can require static methods

In addition to regular instance methods, traits can specify required static
methods.

```mojo
trait HasStaticMethod:
    @staticmethod
    def do_stuff(): ...

def fun_with_traits[type: HasStaticMethod]():
    type.do_stuff()
```

## Default method implementations

Often, some or all of the structs that conform to a given trait can use the same
implementation for a given required method. In this case, the trait can include
a *default implementation*. A conforming struct can still define its own version
of the method, overriding the default implementation. But if the struct doesn't
define its own version, it automatically inherits the default implementation.

Defining a default implementation for a trait looks the same as writing a method
for a struct:

```mojo
trait DefaultQuackable:
    def quack(self):
        print("Quack")

@fieldwise_init
struct DefaultDuck(Copyable, DefaultQuackable):
    pass
```

When looking at the API doc for a standard library trait, you'll see methods
that you *must* implement listed as *required methods*, and methods that have
default implementations listed as *provided methods*.

The
[`Equatable`](/docs/std/builtin/comparable/Equatable/)
trait is a good example of the use case for default implementations. The trait
includes two methods: `__eq__()` (corresponding to the `==` operator) and
`__ne__()` (corresponding to the `!=` operator). Every type that conforms to
`Equatable` needs to define the `__eq__()` method for itself, but the
trait supplies a default implementation for `__ne__()`. Given an `__eq__()`
method, the definition of `__ne__()` is trivial for most types:

```mojo
def __ne__(self, other: Self) -> Bool:
    return not self.__eq__(other)
```

## Trait compositions

You can compose traits using the `&` sigil. This lets you define new traits
that are simple combinations of other traits. You can use a trait composition
anywhere that you'd use a single trait:

```mojo
trait Flyable:
    def fly(self): ...

def quack_and_go[type: Quackable & Flyable](https://mojolang.org/docs/manual/quacker: type.md):
    quacker.quack()
    quacker.fly()

@fieldwise_init
struct FlyingDuck(Copyable, Quackable, Flyable):
    def quack(self):
        print("Quack")

    def fly(self):
        print("Whoosh!")
```

You can also use the `comptime` keyword to create a shorthand name for a
trait composition:

```mojo
comptime DuckLike = Quackable & Flyable

struct ToyDuck(DuckLike):
    # ... implementation omitted
```

You can also compose traits using [refinement](#trait-refinement), by defining
a new, empty trait like this:

```mojo
trait DuckTrait(Quackable, Flyable):
    pass
```

However, this is less flexible than using a trait composition and not
recommended. The difference is that using the `trait` keyword defines a new,
named trait. For a struct to conform to this trait, you need to *explicitly*
include it in the struct's signature. On the other hand, the `DuckLike`
`comptime` value represents a composition of two separate traits, `Quackable`
and `Flyable`, and anything that conforms to those two traits conforms to
`DuckLike`. For example, consider the `FlyingDuck` type shown above:

```mojo
struct FlyingDuck(Copyable, Quackable, Flyable):
    # ... etc
```

Because `FlyingDuck` conforms to both `Quackable` and `Flyable`, it also
conforms to the `DuckLike` trait composition. But it *doesn't*
conform to `DuckTrait`, since it doesn't include `DuckTrait` in its list of
traits.

<a id="trait-inheritance"></a>

## Trait refinement {#trait-refinement}

Traits *refine* other traits. A trait that refines another trait includes all
of the requirements declared by the original trait. For example:

```mojo
trait Animal:
    def make_sound(self):
        ...

# Bird refines Animal
trait Bird(Animal):
    def fly(self):
        ...
```

Since `Bird` refines `Animal`, a struct that conforms to the `Bird` trait
must implement **both** `make_sound()` and `fly()`. And since every `Bird`
conforms to `Animal`, a struct that conforms to `Bird` can be passed to any
function that requires an `Animal`.

You can define a trait as a refinement of multiple traits by listing
them in parentheses. This can be either a comma-separated list of
traits or a trait composition. For example, you might define a
NamedAnimal trait that combines the requirements of the Animal trait
and a new Named trait:

```mojo
trait Named:
    def get_name(self) -> String:
        ...

trait NamedAnimal(Animal, Named):
    def emit_name_and_sound(self):
        ...
```

Refinement is useful when you're creating a new trait that adds additional
requirements. If you simply want to express the union of two or more traits,
use a simple trait composition instead:

```mojo
comptime NamedAnimal = Animal & Named
```

## Traits and lifecycle methods

Traits can specify required
[lifecycle methods](/docs/manual/lifecycle/#lifecycles-and-lifetimes), including
constructors, copy constructors and move constructors.

For example, the following code creates a `MassProducible` trait. A
`MassProducible` type has a default (no-argument) constructor and can be moved.
It uses two built-in traits:
[`Defaultable`](/docs/std/builtin/value/Defaultable/), which requires a default
(no-argument) constructor, and
[`Movable`](/docs/std/builtin/value/Movable/),
which requires the type to have a [move
constructor](/docs/manual/lifecycle/life#move-constructor).

The `factory[]()` function returns a newly-constructed instance of a
`MassProducible` type. The following example shows the definitions of
the `Defaultable` and `Movable` traits in comments for reference:

```mojo
# trait Defaultable
#     def __init__(out self): ...

# trait Movable
#     def __init__(out self, *, deinit take: Self): ...

comptime MassProducible = Defaultable & Movable

def factory[type: MassProducible]() -> type:
    return type()

struct Thing(MassProducible):
    var id: Int

    def __init__(out self):
        self.id = 0

    def __init__(out self, *, deinit take: Self):
        self.id = take.id

var thing = factory[Thing]()
```

### Register passable types and the RegisterPassable trait  {#register-passable}

"Register passable" tells Mojo that a type should be passed in machine
registers such as a CPU register. This means the type is always passed
by value. For data types like an integer or floating-point number, this
is much more efficient than storing values in stack memory.

Mojo supports two forms of register passable types.

The standard *register passable type* has the following capabilities
and restrictions:

- They have normal lifecycles and can implement or override lifecycle
  methods.
- Every field must either be register passable or trivially register
  passable.
- The type must be
  [`Movable`](/docs/manual/lifecycle/life/#move-constructor).
- Their self pointer is neither stable nor predictable. They can move
  in memory at any time so they aren't suitable for types that rely on
  pointer identity.
- When used as arguments or results, they can be exposed directly to C
  and C++ through foreign function interfaces (FFI) and don't need to be
  passed by pointer.
- They can't override the default move constructor. This guarantees
  moves are always side-effect-free.

You can create custom register-passable types by conforming a type
to the `RegisterPassable` trait.

Trivial register types are typically data types. They include:

- *Arithmetic types*. This includes types such as `Int`, `Int32`,
  `Bool`, `Float64` etc.
- *Pointers*. The address value is trivial, not the data being pointed
  to.
- *Arrays of other trivial types*. `SIMD` is a good example.

These types are provided by Mojo's standard library.

A *trivially register passable type* has the following capabilities
and restrictions:

- They do not use lifecycle methods.
- Every field must be trivially register passable.
- The type must be
  [`Copyable`](/docs/manual/lifecycle/life/#copy-constructor).
- They use a special trivial (no-op) destructor. They are _trivially
  movable_ (via `Copyable`, which refines `Movable`), _trivially
  copyable_, and *trivially destructible*.

## Built-in traits

The Mojo standard library includes many traits. They're implemented
by a number of standard library types, and you can also implement these on your
own types. These standard library traits include:

- [`Absable`](/docs/std/math/math/Absable/)
- [`AnyType`](/docs/std/builtin/anytype/AnyType/)
- [`Boolable`](/docs/std/builtin/bool/Boolable/)
- [`Comparable`](/docs/std/builtin/comparable/Comparable/)
- [`Copyable`](/docs/std/builtin/value/Copyable/)
- [`Defaultable`](/docs/std/builtin/value/Defaultable/)
- [`Hashable`](/docs/std/hashlib/hash/Hashable/)
- [`ImplicitlyDestructible`](/docs/std/builtin/anytype/ImplicitlyDestructible/)
- [`Indexer`](/docs/std/builtin/int/Indexer/)
- [`Intable`](/docs/std/builtin/int/Intable/)
- [`IntableRaising`](/docs/std/builtin/int/IntableRaising/)
- [`KeyElement`](/docs/std/collections/dict/#keyelement)
- [`Movable`](/docs/std/builtin/value/Movable/)
- [`PathLike`](/docs/std/os/pathlike/PathLike/)
- [`Powable`](/docs/std/math/math/Powable/)
- [`Sized`](/docs/std/builtin/len/Sized/)
- [`Roundable`](/docs/std/math/math/Roundable/)
- [`Writable`](/docs/std/format/Writable/)
- [`Writer`](/docs/std/format/Writer/)

The API reference docs linked above include usage examples for each trait. The
following sections discuss a few of these traits.

### The `Sized` trait

The [`Sized`](/docs/std/builtin/len/Sized/) trait identifies types that
have a measurable length, like strings and arrays.

Specifically, `Sized` requires a type to implement the `__len__()` method.
This trait is used by the built-in [`len()`](/docs/std/builtin/len/len/)
function. For example, if you're writing a custom list type, you could
implement this trait so your type works with `len()`:

```mojo
struct MyList(Copyable, Sized):
    var size: Int
    # ...

    def __init__(out self):
        self.size = 0

    def __len__(self) -> Int:
        return self.size

print(len(MyList()))
```

```output
0
```

### The `Intable` and `IntableRaising` traits

The [`Intable`](/docs/std/builtin/int/Intable/) trait identifies a type that
can be converted to `Int`. The
[`IntableRaising`](/docs/std/builtin/int/IntableRaising/) trait describes a
type can be converted to an `Int`, but the conversion might raise an error.

Both of these traits require the type to implement the `__int__()` method. For
example:

```mojo
@fieldwise_init
struct IntLike(Intable):
    var i: Int

    def __int__(self) -> Int:
        return self.i

value = IntLike(42)
print(Int(value) == 42)
```

```output
True
```

### The `Writable` trait

Any type that conforms to
[`Writable`](/docs/std/format/Writable/) gets a default implementation
that formats its fields using reflection. Add the trait and you can
print your type:

```mojo
struct SomeType(Writable):
```

[`print()`](/docs/std/io/io/print/) requires its arguments to
conform to `Writable`. This uses stream-based writing and avoids
unnecessary `String` allocations.

Override `write_to()` to control the output format. Write a sequence
of `Writable` values that make up the representation:

```mojo
@fieldwise_init
struct Point(Writable):
    var x: Float64
    var y: Float64

    # Overrides default implementation from Writable conformance
    def write_to(self, mut writer: Some[Writer]):
        writer.write(t"Point({self.x}, {self.y})")

...

var p = Point(1.5, 2.7)
print(p)  # Point(1.5, 2.7)
```

The `Writer` trait only accepts valid UTF-8 text. You can't write
arbitrary bytes. This guarantees that types like `String` can
implement `Writer` without risking corruption.

`Writable` provides
[`write_repr_to()`](/docs/std/format/Writable/#write_repr_to), which
produces a debugging-specific string representation of a value.

`write_repr_to()` has a default implementation based on reflection.
Override it only when your type needs a custom debug representation:

```mojo
# Another method. Overrides default implementation from Writable conformance
def write_repr_to(self, mut writer: Some[Writer]):
    writer.write(t"{self.x} : {self.y}")

print(repr(p))  # 1.5 : 2.7
```

### Lifetime management traits

Mojo provides two core traits for managing value lifetimes:

- [`AnyType`](/docs/std/builtin/anytype/AnyType/): The base trait that all
types conform to. Types conforming only to `AnyType` may require explicit
destruction.

- [`ImplicitlyDestructible`](/docs/std/builtin/anytype/ImplicitlyDestructible/):
Types that can be automatically destroyed by calling `__del__()` when their
lifetime ends.

For detailed information about value destruction, explicit destruction with the
`@explicit_destroy` decorator, and when to use each approach, see [Death of a
value](/docs/manual/lifecycle/death).

## Generic structs with traits

You can also use traits when defining a generic container. A generic container
is a container (for example, an array or hashmap) that can hold different data
types. In a dynamic language like Python it's easy to add different types of
items to a container. But in a statically-typed environment, the compiler needs
to be able to identify the types at compile time. For example, if the container
needs to copy a value, the compiler needs to verify that the type can be copied.

The [`List`](/docs/std/collections/list/) type is an example of a
generic container. A single `List` can only hold a single type of data.
The list elements must conform to the `Copyable` trait:

```mojo
struct List[T: Copyable]:
```

For example, you can create a list of integer values like this:

```mojo
var list: List[Int]
list = [1, 2, 3, 4]
for i in range(len(list)):
    print(list[i], end=" ")
```

```output
1 2 3 4
```

You can use traits to define requirements for elements that are stored in a
container. For example, `List` requires elements that can be moved and
copied. To store a struct in a `List`, the struct needs to conform to
the `Copyable` trait, which requires a
[copy constructor](/docs/manual/lifecycle/life/#copy-constructor) and a
[move constructor](/docs/manual/lifecycle/life/#move-constructor).

Building generic containers is an advanced topic. For an introduction, see the
section on
[parameterized structs](/docs/manual/parameters/#parameterized-structs).

### `comptime` members for generics {#comptime-members-for-generics}

In addition to methods, a trait can include `comptime` members, which must be
defined by any conforming struct. For example:

```mojo
trait Repeater:
    comptime count: Int
```

An implementing struct must define a concrete constant value for the `comptime`
member, using any compile-time parameter value. For example, it can use a
literal constant or a compile-time expression, including one that uses the
struct's parameters.

```mojo
struct Doublespeak(Repeater):
    comptime count: Int = 2

struct Multispeak[verbosity: Int](https://mojolang.org/docs/manual/Repeater.md):
    comptime count: Int = Self.verbosity * 2 + 1
```

The `Doublespeak` struct has a constant value for `count`, but the `Multispeak`
struct lets the user set the value using a parameter:

```mojo
repeater = Multispeak[12]()
```

Note that the field is named `count`, and the `Multispeak` parameter is named
`verbosity`. Parameters and `comptime` members are in the same namespace, so the
parameter can't have the same name as the `comptime` member.

`comptime` members are most useful for writing traits for generic types. For
example, imagine that you want to write a trait that describes a generic stack
data structure that stores elements that conform to the `Copyable`
trait.

By adding the element type as a `comptime` member on the trait, you can specify
generic methods on the trait:

```mojo
trait Stacklike:
    comptime EltType: Copyable

    def push(mut self, var item: Self.EltType):
        ...

    def pop(mut self) -> Self.EltType:
        ...
```

The following struct implements the `Stacklike` trait using a `List` as the
underlying storage:

```mojo
struct MyStack[type: Copyable & ImplicitlyDestructible](https://mojolang.org/docs/manual/Stacklike.md):
    """A simple Stack built using a List."""
    comptime EltType = Self.type
    comptime list_type = List[Self.EltType]

    var list: Self.list_type

    def __init__(out self):
        self.list = Self.list_type()

    def push(mut self, var item: Self.EltType):
        self.list.append(item^)

    def pop(mut self) -> Self.EltType:
        return self.list.pop()

    def dump[
        WritableEltType: Writable & Copyable & ImplicitlyDestructible
    ](https://mojolang.org/docs/manual/self: MyStack[WritableEltType].md):
        print("[", end="")
        for item in self.list:
            print(item, end=", ")
        print("]")
```

The `MyStack` type adds a `dump()` method that prints the contents of the stack.
Because a struct that conforms to `Copyable` is not necessarily
printable, `MyStack` uses
conditional conformance to
define a `dump()` method that works as long as the element type is
[writable](/docs/std/format/Writable/).

The following code exercises this new trait by defining a generic method,
`add_to_stack()` that adds an item to any `Stacklike` type.

```mojo
def add_to_stack[S: Stacklike](https://mojolang.org/docs/manual/mut stack: S, var item: S.EltType):
    stack.push(item^)

def main():
    s = MyStack[Int]()
    add_to_stack(s, 12)
    add_to_stack(s, 33)
    s.dump()             # [12, 33, ]
    print(s.pop())       # 33
```
