Roles
Role composition is flattening with conflict detection: if two roles provide the same method, the class must resolve the conflict explicitly (by defining the method), and compile time tells you if it didn't.
Roles vs classes: classes are for managing instances; roles are for managing behavior and code reuse.
role Greeter {
method greet { "Hello, I'm {self.name}" } # uses a method the class must provide
}
role Serializable {
method to-hash { self.^attributes.map({ .name.substr(2) => .get_value(self) }).Hash }
}
role Comparable {
method compare($other) { ... } # stub (yada): composing classes must implement it
method less-than($other) { self.compare($other) < 0 }
}
class Person does Greeter does Serializable does Comparable {
has $.name;
has $.age;
method compare($other) { $!age <=> $other.age }
}
my $ana = Person.new(name => 'Ana', age => 30);
my $bo = Person.new(name => 'Bo', age => 25);
say $ana.greet; # Hello, I'm Ana
say $ana.to-hash; # {age => 30, name => Ana}
say $bo.less-than($ana); # True
say $ana ~~ Greeter; # True
say Person.^roles; # ((Comparable) (Serializable) (Greeter))
# Roles with attributes
role Timestamped { has DateTime $.created = DateTime.now }
# Parametric roles
role Container[::T] {
has T @.items;
method add(T $item) { @!items.push($item); self }
}
class IntBox does Container[Int] { }
my $box = IntBox.new.add(1).add(2);
say
…