Skip to content

Commit 4172cb1

Browse files
committed
Role punning, parameterized roles
1 parent bc6acd0 commit 4172cb1

File tree

1 file changed

+78
-3
lines changed

1 file changed

+78
-3
lines changed

lib/Language/objects.pod

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,13 +472,13 @@ the role declaration.
472472
473473
Role application differs significantly from class inheritance. When a role
474474
is applied to a class, the methods of that role are copied into the class.
475-
If multiple roles are applied to the same class, conflicts (e.g. non-multi
475+
If multiple roles are applied to the same class, conflicts (e.g. attributes or non-multi
476476
methods of the same name) cause a compile-time error, which can be solved by
477477
providing a method of the same name in the class.
478478
479479
This is much safer than multiple inheritance, where conflicts are never
480480
detected by the compiler, but are instead simply resolved to the superclass
481-
that appears earlier in the MRO, which might or might not be what the
481+
that appears earlier in the method resolution order, which might or might not be what the
482482
programmer wanted.
483483
484484
For example, if you've discovered an efficient method to ride cows, and are
@@ -591,8 +591,83 @@ This allows you to create roles that act as abstract interfaces.
591591
The implementation of the stubbed method may also be provided by another
592592
role.
593593
594+
=head2 Role Punning
595+
596+
Any attempt to instantiate (and many other kinds of usage) a role will
597+
automatically create a class with the same name as the role, making it
598+
possible to transparently use a role as if it were a class.
599+
600+
=begin code
601+
role Point {
602+
has $.x;
603+
has $.y;
604+
method abs { sqrt($.x * $.x + $.y * $.y) }
605+
}
606+
say Point.new(x => 6, y => 8).abs;
607+
=end code
608+
609+
We call this automatic creating of classes I<punning>, and the generated class
610+
a I<pun>.
611+
612+
=head2 Parameterized Roles
613+
614+
Roles can be parameterized, by giving them a signature in square brackets:
615+
616+
=begin code
617+
role BinaryTree[::Type] {
618+
has BinaryTree[Type] $.left;
619+
has BinaryTree[Type] $.right;
620+
has Type $.node;
621+
622+
method visit-preorder(&cb) {
623+
cb $.node;
624+
for $.left, $.right -> $branch {
625+
$branch.visit-preorder(&cb) if defined $branch;
626+
}
627+
}
628+
method visit-postorder(&cb) {
629+
for $.left, $.right -> $branch {
630+
$branch.visit-postorder(&cb) if defined $branch;
631+
}
632+
cb $.node;
633+
}
634+
method new-from-list(::?CLASS:U: *@el) {
635+
my $middle-index = @el.elems div 2;
636+
my @left = @el[0 .. $middle-index - 1];
637+
my $middle = @el[$middle-index];
638+
my @right = @el[$middle-index + 1 .. *];
639+
self.new(
640+
node => $middle,
641+
left => @left ?? self.new-from-list(@left) !! self,
642+
right => @right ?? self.new-from-list(@right) !! self,
643+
);
644+
}
645+
}
646+
647+
my $t = BinaryTree[Int].new-from-list(4, 5, 6);
648+
$t.visit-preorder(&say); # 5 \n 4 \n 6
649+
$t.visit-postorder(&say); # 4 \n 6 \n 5
650+
=end code
651+
652+
Here the signature consists only of a type capture, but any signature will do:
653+
654+
=begin code
655+
use v6;
656+
657+
enum Severity <debug info warn error critical>;
658+
659+
role Logging[$filehandle = $*ERR] {
660+
method log(Severity $sev, $message) {
661+
$filehandle.print("[{uc $sev}] $message\n");
662+
}
663+
}
664+
665+
Logging[$*OUT].log(debug, 'here we go'); # [DEBUG] here we go
666+
=end code
667+
668+
You can have multiple roles of the same name, but with different signatures;
669+
the normal rules of multi dispatch apply for chosing multi candidates.
594670
595-
TODO: parameterized roles
596671
597672
=head1 Meta-Object Programming and Introspection
598673

0 commit comments

Comments
 (0)