Course of Raku / Advanced / Operators / Traits and pragmas 🆕

Writing a trait

Traits are ordinary multi-subroutines with a special name, so you can write your own. To add a trait spelled is something, define a multi sub trait_mod:<is> whose parameters say what it applies to and name the trait:

This is one of the more advanced corners of Raku, so do not worry if it feels intricate. You can use the built-in traits perfectly well without knowing how they are made, and you will rarely need to write one yourself — treat this page as a look under the hood.

my @traced;

multi sub trait_mod:<is>(Routine:D $r, :$traced!) {
    @traced.push($r.name);
}

sub foo() is traced { }
sub bar() is traced { }

say @traced; # [foo bar]

Read the signature: the first parameter, Routine:D $r, is the thing the trait is attached to — here a subroutine. The :D is a type smiley that demands a defined value — an actual routine object, not the bare, undefined Routine type itself. (Its partners are :U, which requires the undefined type object, and :_, which accepts either.) The named parameter :$traced! is the trait’s own name; its presence is what makes is traced call this sub. Because traits run at compile time, both foo and bar are registered as they are declared, so @traced already lists them by the time the program runs — you could even move the say @traced line up above the two sub definitions and it would still print [foo bar].

This tiny trait only records names, but the same mechanism can do much more: wrap a routine to add logging, validate an attribute, or attach metadata. Writing the first parameter as an Attribute or Variable instead of a Routine lets a trait apply to attributes or variables. Traits are how Raku keeps its declaration syntax open — is rw and your own is traced are built the same way.

Course navigation

Quiz — Traits   |   Pragmas


💪 Or jump directly to the exercises in this section.