develooper Front page | perl.moose | Postings from September 2014

Re: role requiring a type

Thread Previous | Thread Next
Karen Etheridge
September 10, 2014 19:48
Re: role requiring a type
Message ID:
On Wed, Sep 10, 2014 at 06:46:28PM +0000, John Macdonald wrote:
> I want to define a role that will use a type defined by its consumer.
> Is this possible, and if so, what is the syntax to code it?


> So, the X::Parent would consume the Generic::Parent role, which would use HashRef[X::Child] as the type for its children attribute; but elsewhere in the same program, there could be a Y::Parent that consumes the same Generic::Parent role but uses HashRef[Y::Child] for the type of its children attribute.
> The only obvious way I can see, is to simply have the Generic::Parent require 'children' and have each specific Parent consumer have to define the attribute themselves (and trust them to all consistently provide a hash of Child objects correctly).  However, that gets very awkward when the role wants to have a bunch of places that should be validating that a child object is consistent with the class of parent object that is consuming the role.  If the consumer has to know all of the internal details of the role and provide the roles data structures for it, that ruins the value of abstracting out the functionality of the role; so I hope there is a better way.

You identified one way - put the type in a sub in the role, and have the
parent use the sub to determine the type when defining the attribute.  But,
if you want to define the attribute itself in the role, but choose between
a variety of types for that attribute, then parameterized roles are just
the thing:

    package X::Parent;
    use Moose;
    use Child::Role => { thing_type => 'X::Child' };

    package Y::Parent;
    use Moose;
    use Child::Role => { thing_type => 'Y::Child' };

    package Child::Role;
    use MooseX::Role::Parameterized;

    parameter thing_type => (
        # intentionally not forcing the type to 'Str'
        required => 1,

    role {
        my $p = shift;
        has children => (
            isa => $p->thing_type,

Note that I left off the type of thing_type, which lets you be flexible
between using stringy types, Moose::Meta::TypeConstraint objects (e.g. via
MooseX::Types), or a Type::Tiny or Types::Standard object, etc etc. As long
as isa() knows what to do with it in the attribute declaration, it can be

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About