With .does
I can check if a type has the role I already know. I'd like to get the list of roles. Inheritance has .^mro
but I didn't see anything like that for roles in the meta model stuff.
Along with that, given a "type", how can I tell if it was defined as a class or a role?
.^roles
say Rat.^roles; # ((Rational[Int,Int]) (Real) (Numeric))
By default it includes every role, including roles brought in by other roles. To only get the first level use :!transitive
Rat.^roles(:!transitive); # ((Rational[Int,Int]))
There's already a good answer to the first question. About the second one, each meta-object has an archetypes
method that in turn carries a range of properties of the types represented by that meta-type. This exists because Perl 6 is open to new meta-types (which might be easier to think about as "types of type"); probably the most widely used example of this today is OO::Monitors
. The archetypes are more focused on what one can do with the type. For example:
> role R { }; say "C: {.composable} I: {.inheritable}" given R.HOW.archetypes;
C: 1 I: 0
> class C { }; say "C: {.composable} I: {.inheritable}" given C.HOW.archetypes;
C: 0 I: 1
The set of available properties can be introspected:
> Int.HOW.archetypes.^methods(:local)
(nominal nominalizable inheritable inheritalizable composable
composalizable generic parametric coercive definite augmentable)
For example, "nominal" means "can this serve as a nominal type", and "augmentable" means "is it allowed to augment this kind of type". The things like "inheritalizable" mean "can I inheritalize such a type" - that is, turn it into a type that I can inherit from even if I can't inherit from this type. A role
is not inheritable, but it is inheritalizable, and the inheritalize operation on it will produce the pun of the role. This is what is happening under the hood when writing something like class C is SomeRole { }
, and means that not only is Perl 6 open to new types of type, but those new types of type can describe how they want to work, if at all, with inheritance and composition.
Being composable with does
is probably the main defining property of a role, and thus the composable
property is likely the best one to use when asking "is this a role". It is also possible to look at the type of the meta-object, as suggested in another answer, but there are multiple meta-objects involved in representing roles (the short name role group, a currying of that group with parameters, and an individual role, plus an internal concretization form that supports the composition process).
> say (role RRR[::T] { }).HOW.^name
Perl6::Metamodel::ParametricRoleHOW
> say RRR.HOW.^name
Perl6::Metamodel::ParametricRoleGroupHOW
> say RRR[Int].HOW.^name
Perl6::Metamodel::CurriedRoleHOW
Thus it's rather more robust to simply check if the thing is composable.
> say (role RRR[::T] { }).HOW.archetypes.composable
1
> say RRR.HOW.archetypes.composable
1
> say RRR[Int].HOW.archetypes.composable
1
Along with that, given a "type", how can I tell if it was defined as a class or a role?
A class is a type whose meta class is of type Metamodel::ClassHOW
:
sub type-classify(Mu \t) {
given t.HOW {
return 'class' when Metamodel::ClassHOW;
return 'role' when Metamodel::ParametricRoleGroupHOW;
}
return 'other';
}
say type-classify(Int); # class
say type-classify(Rational); # role
say type-classify(Bool); # other
Regarding your second question,
given a "type", how can I tell if it was defined as a class or a role?
I haven't found a direct way of doing that. Both classes and roles have Mu in their hierarchy, so that will not distinguish them. However, only classes get to be recognized by (the curiously named) MetaModel::ClassHOW
. So we can hack something like this:
role Ur { }
role F does Ur { }
class G does F { }
for Ur, F, G -> $class-or-role {
CATCH {
default {
say "not classy";
}
}
$class-or-role.say;
$class-or-role.^mro.say;
}
Which will print:
(Ur)
not classy
(F)
not classy
(G)
((G) (Any) (Mu))
, since calling ^mro
on a role will raise an exception. That can be turned into a function for printing out which one is a role, and which is not.