Perl Roles
Tags: perl, programming, oop, role
Published: 2022-01-14 15:34:14

**1. Roles Definition**

A role is a set of methods that provide extra behavior to a class. Roles can't be used independently they need a class to consume them. Roles are a good alternative to inheritance.

**2. A sample role**

A role is declared in a  *.pm file.
```perl
package Role::JSON;
use Moose::Role;

use JSON 'encode_json';

requires qw( data );

sub to_json {
  my $self = shift;

  return encode_json( $self->data() );
}

1;
```
**3. Consuming a role**

In the previous example the Role::JSON _requires_
 the consuming class to have a method named _data_().

```perl
package Foo;
use Moose;
with "Role::JSON";

sub data {
 my $self = shift;
 return { foo => 'bar' }; 
}

__PACKAGE__->meta->make_immutable;

1;
```

Then you could just call the method defined in the role in your program:
```perl

my $obj = Foo->new();

print $obj->to_json();

# And that prints the following JSON
# { foo : 'bar' }

```
 **4. Checking if class consumes a role**

 Because roles are not inherited you cannot use isa() to check if a class consumes a role instead you should use does():
```perl
$object->does("Role::JSON");
```
**5. Roles without Moose/Moo**

Cpan module Role::Tiny allows you to use roles with vanilla OOP not just with Moose or Moo. Like Moose or Moo, Role::Tiny  applies strict and warnings to the caller.
```perl
package Role::Foo;
use Role::Tiny;
sub data { 
 my $self = shift; 
 return { foo => 'bar' };
}
1;

package Bar;
use lib 'lib';
use Role::Tiny::With;
with  'Role::Foo';
....
1;
```
Role::Tiny makes available to your role the following method modifiers: _before_, _around_ and _after_.
In this example when $self->data is called the around block executes and you get JSON returned.
```perl
package Role::JSON;
use Role::Tiny;
use JSON 'encode_json';

requires qw( data );

around data => sub  {
  my $orig = shift;
  my $self = shift;

  return encode_json( $self->$orig() );
};  

```
**6. Compositional safety**
  
Roles attempt to guarantee compositional safety. So, if two roles have the same method defined and you try to consume them in the same class, you will get an error message. 
```perl
 Due to method name conflicts in roles ....
```
Just remember that in order to trigger the error message you need to consume all the roles at once:
```perl
# good
package Foo;
use lib 'lib';
use Role::Tiny::With;
with  'Role::XML', 'Role::JSON';

# bad second method is ignored
package Foo;
use lib 'lib';
use Role::Tiny::With;
with  'Role::XML'; 
with  'Role::JSON';

```
**7. How to fix method collision**
 
- 
implement the methods yourself in your class, thus causing the corresponding role methods to be ignored

- For Moose use the _excludes_ key word
```perl
package Role::JSON;
use Moose::Role;

sub serialize { ... }

package Role::XML;
use Moose::Role;

sub serialize { ... }

package Foo;
use Moose;
with Role::Serializable::JSON,
     Role::Serializable::XML => { excludes => 'serialize' };
```

- For Role::Tiny use  namespace::clean
```perl
package Role::XML;

use Role::Tiny;

sub serialize { my $self = shift; print 'test'  };
# serialize() will not be imported in the consuming class
use namespace::clean;

1;
```
**8. Bibliography**

- [Beginning Perl by Curtis 'Ovid' Poe ](https://www.amazon.com/Beginning-Perl-Curtis-Poe-ebook-dp-B009K92D9I/dp/B009K92D9I/ref=mt_other?_encoding=UTF8&me=&qid=)
- [Modern Perl by Chromatic](http://modernperlbooks.com/)
- [Use roles in object oriented Perl with Role::Tiny by David Farrell](https://www.perl.com/article/47/2013/11/11/Use-roles-in-object-oriented-Perl-with-Role-Tiny/)