@@ -472,13 +472,13 @@ the role declaration.
472
472
473
473
Role application differs significantly from class inheritance. When a role
474
474
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
476
476
methods of the same name) cause a compile-time error, which can be solved by
477
477
providing a method of the same name in the class.
478
478
479
479
This is much safer than multiple inheritance, where conflicts are never
480
480
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
482
482
programmer wanted.
483
483
484
484
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.
591
591
The implementation of the stubbed method may also be provided by another
592
592
role.
593
593
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.
594
670
595
- TODO: parameterized roles
596
671
597
672
= head1 Meta-Object Programming and Introspection
598
673
0 commit comments