Skip to content

Traits

We've briefly covered traits in the Basic types chapter. In this chapter we'll take a closer look at them.

Traits are like interfaces found in other languages, with one key difference: you can define default method implementations in a trait. Using traits we can compose behaviour, without the limitations and complications of inheritance.

Defining traits

You can define a trait using the trait keyword, followed by its name and a pair of curly braces:

trait ToString {

}

You can't create an instance of a trait. Instead, traits act like blueprints to be implemented by objects.

Implementing traits

A trait is implemented using the impl keyword, like so:

trait ToString {

}

object Number {

}

impl ToString for Number {

}

Inko uses nominal typing, so a trait is not implemented unless you explicitly do so using the impl keyword.

A trait can only be implemented once for an object. If a method in a trait conflicts with that of another trait, the trait can't be implemented; requiring you to resolve the conflict somehow.

Note

Renaming methods when implementing traits is not supported. We may add support for this in the future.

Trait requirements

When defining a trait, you can specify one or more traits as requirements. When an object implements a trait with one or more of such requirements, the object must also implement those traits:

trait ToString {

}

trait Display: ToString {

}

Here the Display trait states that the ToString trait must also be implemented. You can also specify multiple requirements:

trait ToString {

}

trait Format {

}

trait Display: ToString + Format {

}

Required methods

Traits can define methods that an object must implement. To define a required method, use the def keyword like regular methods and leave out the method body:

trait ToString {
  def to_string -> String
}

Required methods can also specify arguments:

trait Printer {
  def print(value: String) -> String
}

Unlike regular methods, required methods can't use default values for arguments. This means the following is invalid:

trait Printer {
  def print(value = 'foo') -> String
}

Default methods

We define default methods like any other method. When an object implements a trait with a default method, that method becomes available to the object. An object is free to redefine the default method's implementation:

trait ToString {
  def to_string -> String {
    ''
  }
}

object Fireworks {

}

impl ToString for Fireworks {
  def to_string -> String {
    'Boom!'
  }
}