Types, classes & roles

Roles

Full

Reusable bundles of behaviour composed into classes with does.

A role packages methods (and attributes) for reuse. A class composes a role with does, flattening the role's members into the class. Roles are Raku's preferred alternative to deep inheritance for sharing behaviour.

Composing a role #

role Greet {
    method hello { "Hi, I am " ~ self.name }
}
class Person does Greet {
    has $.name;
}
say Person.new(name => "Ada").hello;
Output
Hi, I am Ada

The role's hello becomes a method of Person, and self.name resolves against the composing class's attribute.

Required methods — an interface #

A role can require a method by leaving its body as a stub ({ ... }). The role's own methods may call it, and the composing class supplies the implementation — an interface contract.

role Speaker {
    method speak { ... }                      # required
    method announce { "It says: " ~ self.speak }
}
class Dog does Speaker {
    method speak { "woof" }
}
say Dog.new.announce;
Output
It says: woof

Composing several roles #

A class can compose any number of roles; their methods all flatten in together.

role Walks { method move { "walk" } }
role Swims { method swim { "swim" } }
class Duck does Walks does Swims { }
say Duck.new.move ~ " and " ~ Duck.new.swim;
Output
walk and swim

Parameterized roles #

A role can take a type parameter in […], so one role generates a family of typed behaviours.

role Container[::T] {
    has T @.items;
    method count { @.items.elems }
}
class IntBox does Container[Int] { }
say IntBox.new(items => [1, 2, 3]).count;
Output
3

Notes #