Perl has an internal psuedo-module called UNIVERSAL
which all modules inherit from. It has a method called DOES
, from the docs on UNIVERSAL
.
$obj->DOES( ROLE )
CLASS->DOES( ROLE )
DOES
checks if the object or class performs the roleROLE
. A role is a named group of specific behavior (often methods of particular names and signatures), similar to a class, but not necessarily a complete class by itself. For example, logging or serialization may be roles.
DOES
andisa
are similar, in that if either is true, you know that the object or class on which you call the method can perform specific behavior. However,DOES
is different fromisa
in that it does not care how the invocand performs the operations, merely that it does. (isa
of course mandates an inheritance relationship. Other relationships include aggregation, delegation, and mocking.)There is a relationship between roles and classes, as each class implies the existence of a role of the same name. There is also a relationship between inheritance and roles, in that a subclass that inherits from an ancestor class implicitly performs any roles its parent performs. Thus you can use
DOES
in place ofisa
safely, as it will return true in all places whereisa
will return true (provided that any overriddenDOES
andisa
methods behave appropriately).
I know Moose et al provide a DOES
, and I understand how this is used. But in the sense of UNIVERSAL::DOES
what is a ROLE
? How are they tracked? How are they created aside from Moose to satisfy DOES
? I tried looking in the source, but the implementation of DOES
was not provided. Is this notion of a ROLE
something in CORE
perl? This seems to be related to the perldoc perlapi
's mention of sv_does_sv
(also sv_does
/sv_does_pv
)
sv_does_sv
Returns aboolean
indicating whether theSV
performs a specific, named role. TheSV
can be a Perl object or the name of a Perl class.
bool sv_does_sv(SV* sv, SV* namesv, U32 flags)
I can see a call to sv_does_sv
in the implementation of universal.c
. What's the definition of a SV role? Where can I find more information about this?
From the user-level, what does the code here do, (this is a subref)
UNIVERSAL->can('DOES')
The address returned is different from UNIVERSAL->can('isa')
in the same invocation so it's doing something different, and I can see that muck in the above linked universal.c
.
Roles are a label for a set of methods that a class provides. Similar to traits in Smalltalk or an interface in Java, adding a Perl role to a class is like adding a guarantee that the class will implement that role's API.
@ISA. Each package contains a special array called @ISA which contains a list of that class's parent classes, if any. This array is simply a list of scalars, each of which is a string that corresponds to a package name. The array is examined when Perl does method resolution, which is covered in perlobj.
The can() method accepts the method's name as a string. It returns a reference to the existing function that implements this method or else it returns a false value. This method can be called on a class, object, or a package.
The UNIVERSAL::DOES
is equivalent to:
sub DOES {
croak "Usage: invocant->DOES(kind)"
if @_ != 2;
$_[0]->isa($_[1]);
}
Internally, sv_does_sv
calls the isa
method on the first SV it is passed. perl itself doesn't provide an implementation of roles, so it is left to the role modules to provide a DOES
that accounts for them.
The convention in Moose, Moo, Role::Tiny, Mouse, etc, is that the DOES
method is true for class and its parent classes, and the roles that the class and its parent classes compose. These libraries also provide the does
method, which is only true for the composed roles of the class and its parent classes, but not class or its parent classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With