Skip to content

Commit 9518b15

Browse files
authored
add example about Pecking order
and unify format, fix typo
1 parent b5a8939 commit 9518b15

File tree

1 file changed

+99
-79
lines changed

1 file changed

+99
-79
lines changed

doc/Language/objects.pod6

Lines changed: 99 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -617,42 +617,42 @@ describing only parts of an object's behavior and in how roles are applied
617617
to classes. Or to phrase it differently, classes are meant for managing
618618
objects and roles are meant for managing behavior and code reuse.
619619
620-
=begin code :allow<B L>
620+
=begin code
621621
use MONKEY-SEE-NO-EVAL;
622622
role Serializable {
623623
method serialize() {
624-
self.L<perl>; # very primitive serialization
624+
self.perl; # very primitive serialization
625625
}
626626
method deserialize($buf) {
627-
L<EVAL|/routine/EVAL> $buf; # reverse operation to .perl
627+
EVAL $buf; # reverse operation to .perl
628628
}
629629
}
630630
631-
class Point B<does> Serializable {
631+
class Point does Serializable {
632632
has $.x;
633633
has $.y;
634634
}
635635
my $p = Point.new(:x(1), :y(2));
636-
my $serialized = $p.serialize; # method provided by the role
636+
my $serialized = $p.serialize;
637637
my $clone-of-p = Point.deserialize($serialized);
638-
say $clone-of-p.x; # OUTPUT: «1␤»
638+
say $clone-of-p.x; # OUTPUT: «1␤»
639639
=end code
640640
641641
Roles are immutable as soon as the compiler parses the closing curly brace of
642642
the role declaration.
643643
644-
=head2 Z<>Role Application
644+
=head2 Role Application
645645
646646
Role application differs significantly from class inheritance. When a role
647647
is applied to a class, the methods of that role are copied into the class.
648-
If multiple roles are applied to the same class, conflicts (e.g. attributes or non-multi
649-
methods of the same name) cause a compile-time error, which can be solved by
650-
providing a method of the same name in the class.
648+
If multiple roles are applied to the same class, conflicts (e.g.
649+
attributes or non-multi methods of the same name) cause a compile-time error,
650+
which can be solved by providing a method of the same name in the class.
651651
652652
This is much safer than multiple inheritance, where conflicts are never
653653
detected by the compiler, but are instead resolved to the superclass
654-
that appears earlier in the method resolution order, which might not be what the
655-
programmer wanted.
654+
that appears earlier in the method resolution order, which might not
655+
be what the programmer wanted.
656656
657657
For example, if you've discovered an efficient method to ride cows, and are
658658
trying to market it as a new form of popular transportation, you might have
@@ -674,10 +674,11 @@ C<Automobile>, for things that you can drive.
674674
class Taurus is Bull is Automobile { }
675675
676676
my $t = Taurus.new;
677-
$t.steer; # OUTPUT: «Castrates $t␤»
677+
say $t.steer;
678+
# OUTPUT: «Taurus.new(castrated => Bool::True, direction => Any)␤»
678679
679680
With this setup, your poor customers will find themselves unable to turn
680-
their Taurus and you won't be able to make more of your product! In this
681+
their Taurus and you won't be able to make more of your product! In this
681682
case, it may have been better to use roles:
682683
683684
=begin code :skip-test
@@ -708,7 +709,7 @@ This code will die with something like:
708709
709710
This check will save you a lot of headaches:
710711
711-
=begin code :skip-test
712+
=begin code :preamble<role Bull-Like{}; role Steerable{};>
712713
class Taurus does Bull-Like does Steerable {
713714
method steer($direction?) {
714715
self.Steerable::steer($direction?)
@@ -740,19 +741,21 @@ produces the same class C<C> as
740741
741742
=head2 Stubs
742743
743-
When a role contains a stubbed method, a non-stubbed version of a method of
744-
the same name must be supplied at the time the role is applied to a class.
745-
This allows you to create roles that act as abstract interfaces.
744+
When a role contains a L<stubbed|/routine/...> method,
745+
a non-stubbed version of a method of the same name must be supplied
746+
at the time the role is applied to a class. This allows you to
747+
create roles that act as abstract interfaces.
746748
747-
=begin code :allow<B L> :skip-test
749+
=begin code :skip-test
748750
role AbstractSerializable {
749-
method serialize() { B<L<...>> } # literal ... here marks the
751+
method serialize() { ... } # literal ... here marks the
750752
# method as a stub
751753
}
752754
753755
# the following is a compile time error, for example
754756
# Method 'serialize' must be implemented by Point because
755757
# it's required by a role
758+
756759
class APoint does AbstractSerializable {
757760
has $.x;
758761
has $.y;
@@ -772,103 +775,120 @@ role.
772775
=head2 Inheritance
773776
774777
Roles cannot inherit from classes, but they may cause any class which does
775-
that role to inherit from another class. So if you write:
778+
that role to inherit from another class. So if you write:
776779
777780
=begin code
778781
role A is Exception { }
779782
class X::Ouch does A { }
780783
X::Ouch.^parents.say # OUTPUT: «((Exception))␤»
781784
=end code
782785
783-
...then C<X::Ouch> will inherit directly from Exception, as we can see above
786+
then C<X::Ouch> will inherit directly from Exception, as we can see above
784787
by listing its parents.
785788
786789
=head2 Pecking order
787790
788791
A method defined directly in a class will always override definitions from
789-
applied roles or from inherited classes. If no such definition exists, methods
790-
from roles override methods inherited from classes. This happens both when
792+
applied roles or from inherited classes. If no such definition exists, methods
793+
from roles override methods inherited from classes. This happens both when
791794
said class was brought in by a role, and also when said class was inherited
792795
directly.
793796
794-
Note that each candidate for a multi-method is its own method... in this case,
797+
role M {
798+
method f { say "I am in role M" }
799+
}
800+
801+
class A {
802+
method f { say "I am in class A" }
803+
}
804+
805+
class B is A does M {
806+
method f { say "I am in class B" }
807+
}
808+
809+
class C is A does M { }
810+
811+
B.new.f; # OUTPUT «I am in class B␤»
812+
C.new.f; # OUTPUT «I am in role M␤»
813+
814+
Note that each candidate for a multi-method is its own method. In this case,
795815
the above only applies if two such candidates have the same signature.
796816
Otherwise, there is no conflict, and the candidate is just added to the
797817
multi-method.
798818
799819
=head2 Automatic Role Punning
800820
801-
Any attempt to directly instantiate a role, as well as many other operations on it,
802-
will automatically create an instance of a class with the same name as the role, making it
803-
possible to transparently use a role as if it were a class.
821+
Any attempt to directly instantiate a role, as well as many other operations
822+
on it, will automatically create an instance of a class with the same name as
823+
the role, making it possible to transparently use a role as if it were a class.
804824
805-
=begin code
806-
role Point {
807-
has $.x;
808-
has $.y;
809-
method abs { sqrt($.x * $.x + $.y * $.y) }
810-
}
811-
say Point.new(x => 6, y => 8).abs;
812-
=end code
825+
=begin code
826+
role Point {
827+
has $.x;
828+
has $.y;
829+
method abs { sqrt($.x * $.x + $.y * $.y) }
830+
}
831+
say Point.new(x => 6, y => 8).abs; # OUTPUT «10␤»
832+
=end code
813833
814834
We call this automatic creation of classes I<punning>, and the generated class
815835
a I<pun>.
816836
817837
=head2 Parameterized Roles
838+
818839
X<|Parameterized Roles>
819-
Roles can be parameterized, by giving them a signature in square brackets:
820840
821-
=begin code
822-
role BinaryTree[::Type] {
823-
has BinaryTree[Type] $.left;
824-
has BinaryTree[Type] $.right;
825-
has Type $.node;
841+
Roles can be parameterized, by giving them a signature in square brackets:
826842
827-
method visit-preorder(&cb) {
828-
cb $.node;
829-
for $.left, $.right -> $branch {
830-
$branch.visit-preorder(&cb) if defined $branch;
843+
=begin code
844+
role BinaryTree[::Type] {
845+
has BinaryTree[Type] $.left;
846+
has BinaryTree[Type] $.right;
847+
has Type $.node;
848+
849+
method visit-preorder(&cb) {
850+
cb $.node;
851+
for $.left, $.right -> $branch {
852+
$branch.visit-preorder(&cb) if defined $branch;
853+
}
831854
}
832-
}
833-
method visit-postorder(&cb) {
834-
for $.left, $.right -> $branch {
835-
$branch.visit-postorder(&cb) if defined $branch;
855+
method visit-postorder(&cb) {
856+
for $.left, $.right -> $branch {
857+
$branch.visit-postorder(&cb) if defined $branch;
858+
}
859+
cb $.node;
860+
}
861+
method new-from-list(::?CLASS:U: *@el) {
862+
my $middle-index = @el.elems div 2;
863+
my @left = @el[0 .. $middle-index - 1];
864+
my $middle = @el[$middle-index];
865+
my @right = @el[$middle-index + 1 .. *];
866+
self.new(
867+
node => $middle,
868+
left => @left ?? self.new-from-list(@left) !! self,
869+
right => @right ?? self.new-from-list(@right) !! self,
870+
);
836871
}
837-
cb $.node;
838-
}
839-
method new-from-list(::?CLASS:U: *@el) {
840-
my $middle-index = @el.elems div 2;
841-
my @left = @el[0 .. $middle-index - 1];
842-
my $middle = @el[$middle-index];
843-
my @right = @el[$middle-index + 1 .. *];
844-
self.new(
845-
node => $middle,
846-
left => @left ?? self.new-from-list(@left) !! self,
847-
right => @right ?? self.new-from-list(@right) !! self,
848-
);
849872
}
850-
}
851873
852-
my $t = BinaryTree[Int].new-from-list(4, 5, 6);
853-
$t.visit-preorder(&say); # OUTPUT: «5␤4␤6␤»
854-
$t.visit-postorder(&say); # OUTPUT: «4␤6␤5␤»
855-
=end code
874+
my $t = BinaryTree[Int].new-from-list(4, 5, 6);
875+
$t.visit-preorder(&say); # OUTPUT: «5␤4␤6␤»
876+
$t.visit-postorder(&say); # OUTPUT: «4␤6␤5␤»
877+
=end code
856878
857879
Here the signature consists only of a type capture, but any signature will do:
858880
859-
=begin code
860-
use v6.c;
861-
862-
enum Severity <debug info warn error critical>;
881+
=begin code
882+
enum Severity <debug info warn error critical>;
863883
864-
role Logging[$filehandle = $*ERR] {
865-
method log(Severity $sev, $message) {
866-
$filehandle.print("[{uc $sev}] $message\n");
884+
role Logging[$filehandle = $*ERR] {
885+
method log(Severity $sev, $message) {
886+
$filehandle.print("[{uc $sev}] $message\n");
887+
}
867888
}
868-
}
869889
870-
Logging[$*OUT].log(debug, 'here we go'); # OUTPUT: «[DEBUG] here we go␤»
871-
=end code
890+
Logging[$*OUT].log(debug, 'here we go'); # OUTPUT: «[DEBUG] here we go␤»
891+
=end code
872892
873893
You can have multiple roles of the same name, but with different signatures;
874894
the normal rules of multi dispatch apply for choosing multi candidates.
@@ -924,8 +944,8 @@ objects; those objects are called I<meta objects>. Meta objects are, like
924944
ordinary objects, instances of classes, in this case we call them I<meta
925945
classes>.
926946
927-
For each object or class you can get the meta object by calling C<.HOW> on
928-
it. Note that although this looks like a method call, it works more like a macro.
947+
For each object or class you can get the meta object by calling C<.HOW> on it.
948+
Note that although this looks like a method call, it works more like a macro.
929949
930950
So, what can you do with the meta object? For one you can check if two
931951
objects have the same meta class by comparing them for equality:

0 commit comments

Comments
 (0)