Course of Raku / Objects, I/O, and exceptions / Classes and objects / Roles

Adding a role to an object

A role does not have to be baked into a class. You can also give one to an object that already exists, using the but operator. It mixes the role into a single object at run time and returns a new object that plays the role:

role Loud {
    method greet {
        callsame().uc;
    }
}

class Greeter {
    method greet {
        'Hello';
    }
}

my $quiet = Greeter.new;
my $loud  = Greeter.new but Loud;

say $quiet.greet; # Hello
say $loud.greet;  # HELLO

Only $loud gained the role. The Greeter class and every other Greeter object are untouched, so $quiet still greets in the ordinary way. When the role and the class both define a method with the same name, the role’s version wins, and callsame calls the one it overrode — here the original greet from Greeter, whose result is then upper-cased.

An object that has a role mixed in is recognised as doing that role:

say $quiet ~~ Loud; # False
say $loud  ~~ Loud; # True

but leaves the original object as it was and hands you a new one. If you would rather change an existing object in place, use the does operator instead:

my $speaker = Greeter.new;
$speaker does Loud;
say $speaker.greet; # HELLO

Mixing roles into individual objects lets you decide, one object at a time, which extra behaviour it should take on — without defining a separate class for every combination.

Practice

Complete the quiz that covers the contents of this topic.

Course navigation

Composing several roles   |   Quiz — Roles


💪 Or jump directly to the exercises in this section.