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 )
DOESchecks 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.
DOESandisaare 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,DOESis different fromisain that it does not care how the invocand performs the operations, merely that it does. (isaof 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
DOESin place ofisasafely, as it will return true in all places whereisawill return true (provided that any overriddenDOESandisamethods 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_svReturns abooleanindicating whether theSVperforms a specific, named role. TheSVcan 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