📘 Roles in Perl 6

📘 Roles in Raku

N. B. Perl 6 has been renamed to Raku. Click to read more.


Apart from the bare classes, the Perl 6 language allows roles. These are what are sometimes called interfaces in other object-oriented languages. Both the methods and the data, which are defined in a role, are available for “addition” (or mixing-in) to a new class with the help of the does keyword.

A role looks like a base class that appends its methods and data to generate a new type. The difference between prepending a role and deriving a class from a base class is that with a role, you do not create any inheritance. Instead, all the fields from the role become the fields of an existing class. In other words, classes are the is a characteristic of an object, while roles are the does traits. With roles, name conflicts will be found at compile time; there is no need to traverse the method resolution order paths.

The following example defines a role, which is later used to create two classes; we could achieve the same with bare inheritance, though:

# The role of the catering place is to take orders 
# (via the order method), to count the total amount 
# of the order (method calc) and issuing a bill (method bill).

role FoodService {
    has @!orders;

    method order($price) {
        @!orders.push($price);
    }

    method calc {
        # [+] is a hyperoperator (hyperop) connecting all the
        # elements of an array.
        # It means that [+] @a is equivalent to
        # @a[0] + @a[1] + ... + @a[N].
        return [+] @!orders;
    }

    method bill {
        # Order's total is still a sum of the orders.
        return self.calc;
    }
}

# Launching a cafe. A cafe is a catering place.
class Cafe does FoodService {
    method bill {
        # But with a small surcharge.
        return self.calc * 1.1;
    }
}

# And now a restaurant.
class Restaurant does FoodService {
    method bill {
        # First, let the customer wait some time.
        sleep 10.rand;

        # Second, increase the prices even more.
        return self.calc * 1.3;
    }
}

Let us try that in action. First, the cafe.

my $cafe = Cafe.new;
$cafe.order(10);
$cafe.order(20);
say $cafe.bill; # Immediate 33

Then, the restaurant. (Note that this code will have a delay because of the class definition).

my $restaurant = Restaurant.new;
$restaurant.order(100);
$restaurant.order(200);
say $restaurant.bill; # 390 after some unpredictable delay

Roles can be used for defining and API and forcing the presence of a method in a class that uses a role. For example, let’s create a role named Liquid, which requires that the flows method must be implemented.

role Liquid {
    method flows {...}
}

class Water does Liquid {
}

It is not possible to run this programme as it generates a compile-time error:

Method 'flows' must be implemented by Water because it is required by a role

Note that the ellipsis … is a valid Perl 6 construction that is used to create forward declarations.

Leave a Reply

Your email address will not be published. Required fields are marked *

Retype the CAPTCHA code from the image
Change the CAPTCHA codeSpeak the CAPTCHA code