Traits
Share method implementations between types.
On this page
A trait is a set of methods that classes and structs copy into their own body with use. Use it to share an implementation; use an interface when callers need to accept different classes.
Use a trait#
Valk
trait Labeled {
fn label() String {
return "Item: " + this.name
}
}
class Folder {
name: String
use Labeled
}
struct Tag {
name: String
use Labeled
}
fn main() {
println(Folder { name: "Reports" }.label()) // Item: Reports
println(Tag { name: "urgent" }.label()) // Item: urgent
}
The trait's methods are checked inside each type that uses them, so this.name works because both types have a name property.
Generic traits#
A trait can take type parameters, given at the use:
Valk
trait Wrapper[T] {
fn wrap(value: T) Array[T] {
return Array[T]{ value }
}
}
class Box {
use Wrapper[String]
}
fn main() {
println(Box{}.wrap("x").length) // 1
}
Replace a trait method#
A method the type defines itself replaces the trait's method with the same name. The trait's other methods then call the type's version:
Valk
trait Greeter {
fn name() String { return "someone" }
fn greet() String { return "Hello " + this.name() }
}
class Person {
first: String
use Greeter
fn name() String { return this.first }
}
fn main() {
println(Person { first: "Ada" }.greet()) // Hello Ada
}
When two traits define the same method, the type must define that method itself.
Traits and interfaces together#
A trait can supply the methods an interface asks for:
Valk
interface Named {
fn display() String;
}
trait DisplayName {
fn display() String { return "<" + this.name + ">" }
}
class User is Named {
name: String
use DisplayName
}
fn show(item: Named) {
println(item.display())
}
fn main() {
show(User { name: "ada" }) // <ada>
}
