/
objects.pod
758 lines (587 loc) · 23 KB
/
objects.pod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
=begin pod
=TITLE Object Orientation
=SUBTITLE Object Orientation in Perl 6
Perl 6 is an object oriented language at its core, even though it allows you
to write programs in other programming styles.
Perl 6 comes with a wealth of predefined types, which can be classified in
two categories: normal and I<native> types.
Native types are used for low-level types (like C<uint64>). They do not have
the same capabilities as objects, though if you call methods on them, they
are I<boxed> into normal objects.
Everything that you can store in a variable is either a native value or an
object. That includes literals, types (type objects), code and containers.
=head1 Using Objects
You can use objects by calling methods on them. To call a method on an
expression, add a dot, followed by the method name:
=for code :allow<B L>
L<say> "abc"B<.L<uc>>;
# ABC
This calls the L<C<uc>|uc> method on C<"abc">, which is an object of type
L<C<Str>|Str>. If you need to supply arguments to the method, add
parentheses after the method name with the arguments inside the parentheses:
=for code :allow<B L>
my $formatted-text = "Fourscore and seven years ago...".L<indent>B<(8)>;
C<$formatted-text> now contains the above text, but indented 8 spaces.
Multiple arguments simply require a comma between them:
=for code :allow<B L>
my @words = "Abe", "Lincoln";
@words.L<push>("said"B<,> $formatted-text.L<comb>(L</\w+/|/language/regexes>));
Another method call syntax separates the method name and the argument list
with a colon:
=for code :allow<B L>
say @words.L<join>: '--';
# Abe--Lincoln--said--Fourscore--and--seven--years--ago
Since you have to put a C<:> after the method if you want to pass arguments
without parentheses, a method call without a colon or parens is
unambiguously a method call without an argument list:
say 4.log: ; # 1.38629436111989 ( natural logarithm of 4 )
say 4.log: +2; # 2 ( base-2 logarithm of 4 )
say 4.log +2; # 3.38629436111989 ( natural logarithm of 4, plus 2 )
Many operations that don't look like method calls (for example, smart
matching, or interpolating an object into a string) result in method calls
under the hood.
Methods can return mutable containers, in which case you can assign to the
return value of a method call. This is how read-writable attributes to
objects are used:
=for code :allow<L>
$*IN.L<input-line-separator> = "\r\n";
Here, we are call the method C<input-line-separator> on the C<$*IN> object,
give it no arguments, and assign to the container it returned with the
L<C<=>|=> operator.
All objects support the methods from class L<Mu>, which is the root of the
type hierarchy. In other words, all objects are derived from C<Mu>.
=head2 Type Objects
Types themselves are objects and you can get the I<type object> simply by
writing its name:
my $int-type-obj = Int;
You can ask any object for its type object by calling the C<WHAT> method
(which is actually a macro in method form):
my $int-type-obj = 1.WHAT;
Type objects (other than L<Mu>) can be compared for equality with the
L<C<===>|===> identity operator:
=for code :allow<B L>
sub f(Int $x) {
if $x.WHAT B<L<===>> Int {
say 'you passed an Int';
}
else {
say 'you passed a subtype of Int';
}
}
Although, in most cases, the L<C<.isa>|isa> method will suffice:
=for code :allow<B L>
sub f($x) {
if $xB<.L<isa>>(Int) {
...
}
...
}
Subtype checking is done by smart-matching:
=for code :allow<B L>
if $type B<L<~~>> L<Real> {
say '$type contains Real or a subtype thereof';
}
=head1 X<Classes|declarator,class>
Classes are declared using the C<class> keyword, typically followed by a
name.
class Journey {
}
This declaration results in a type object being created and installed in the
current package and current lexical scope under the name C<Journey>. You
can also declare classes lexically:
my class Journey {
}
This restricts their visibility to the current lexical scope, which can be
useful if the class is an implementation detail nested inside a module or
another class.
=head2 Attributes
Attributes are variables that exist per instance of a class. They are where
the state of an object is stored. In Perl 6, all attributes are private.
They are typically declared using the C<has> declarator and using the C<!>
twigil.
class Journey {
has $!origin;
has $!destination;
has @!travellers;
has $!notes;
}
While there is no such thing as a public (or even protected) attribute,
there is a way to have accessor methods generated automatically: replace the
C<!> twigil with the C<.> twigil (the C<.> should remind you of a method
call).
class Journey {
has $.origin;
has $.destination;
has @!travellers;
has $.notes;
}
This defaults to providing a read-only accessor. In order to allow changes
to the attribute, add the C<rw> trait:
class Journey {
has $.origin;
has $.destination;
has @!travellers;
has $.notes is rw;
}
Now, after a C<Journey> object is created, its C<.origin>, C<.destination>,
and C<.notes> will all be accessible from outside the class, but only
C<.notes> can be modified.
Since classes inherit a default constructor from C<Mu> and we have requested
that some accessor methods are generated for us, our class is already
somewhat functional.
=begin code :allow<B L>
# Create a new instance of the class.
my $vacation = Journey.new(
origin L«=>» 'Sweden',
destination => 'Switzerland',
notes => 'Pack hiking gear!'
);
# Use an accessor; this outputs Sweden.
say $vacation.origin;
# Use an rw accessor to change the value.
$vacation.notes = 'Pack hiking gear and sunglasses!';
=end code
Note that the default constructor will only set attributes that have an
accessor method, but it can initialize read-only attributes.
=head2 Methods
Methods are declared with the C<method> keyword inside a class body.
=begin code :allow<B L>
class Journey {
has $.origin;
has $.destination;
has @!travellers;
has $.notes is rw;
B<method> add_traveller($name) {
if $name L<ne> L<any>(@!travellers) {
L<push> @!travellers, $name;
}
else {
L<warn> "$name is already going on the journey!";
}
}
B<method> describe() {
"From $!origin to $!destination"
}
}
=end code
A method can have a signature, just like a subroutine. Attributes can be
used in methods and can always be used with the C<!> twigil, even if they
are declared with the C<.> twigil. This is because really, the C<.> twigil
declares a C<!> twigil and then additionally generates an accessor method.
There is a subtle but important difference between using, say, C<$!origin>
and C<$.origin> in the method C<describe>. The first is always a simple
lookup of the attribute. It is cheap, and you know that it is the attribute
declared in this class. The latter is really a method call and thus it may
be overridden in a subclass. Only use C<$.origin> if you explicitly want to
allow overriding.
=head2 self
Inside a method, the term C<self> is available, which is bound to the
invocant, i.e. the object that the method was called on. C<self> can be
used to call further methods on the invocant. Within methods, something like
C<$.origin> is the same thing as C<self.origin>.
=head2 Private Methods
Methods strictly for use inside the class and that are not to be called from
anywhere else are declared with an exclamation mark C<!> before the method
name. They are called with an exclamation mark instead of a dot:
method !do-something-private($x) {
...
}
method public($x) {
if self.precondition {
self!do-something-private(2 * $x)
}
}
Private methods are not inherited to subclasses.
=head2 Submethods
A submethod is a public method that is not inherited to subclasses. The name
stems from the fact that they are semantically similar to subroutines.
Submethods are useful for object construction and destruction tasks, as well
as for tasks that are so specific to a certain type that subtypes must
certainly override them.
For example the L<default method new|/type/Mu#method new> calls submethod
C<BUILD> on each class in an L<inheritance|#Inheritance> chain:
=begin code
class Point2D {
has $.x;
has $.y;
submethod BUILD(:$!x, :$!y) {
say "Initializing Point2D";
}
}
class InvertiblePoint2D is Point2D {
submethod BUILD() {
say "Initializing InvertiblePoint2D";
}
method invert {
self.new(x => - $.x, y => - $.y);
}
}
say InvertiblePoint2D.new(x => 1, y => 2);
=end code
This produces the following output:
=begin code
Initializing Point2D
Initializing InvertiblePoint2D
InvertiblePoint2D.new(x => 1, y => 2)
=end code
See also: L<#Object Construction>.
=head2 Inheritance
Classes can have I<parent classes>.
=for code :allow<B L>
class Child B<L<is> Parent1 is Parent2> { }
If a method is called on the child class, and the child class does not
provide that method, the method of that name in one of the parent classes is
invoked instead, if it exists. The order in which parent classes are
consulted is called the I<method resolution order> (MRO). Perl 6 uses the
L<C3 method resolution
order|https://en.wikipedia.org/wiki/C3_linearization>. You can ask a type
for its MRO through a call to its meta class:
=for code :allow<B L>
say ParcelB<.^L<mro>>; # Parcel() Cool() Any() Mu()
If a class does not specify a parent class, L<Any> is assumed by default.
All classes directly or indirectly derive from L<Mu>, the root of the type
hierarchy.
All calls to public methods are "virtual" in the C++ sense, which means that
the actual type of an object determines which method to call, not the
declared type:
=begin code
class Parent {
method frob {
say "the parent class frobs"
}
}
class Child is Parent {
method frob {
say "the child's somewhat more fancy frob is called"
}
}
my Parent $test;
$test = Child.new;
$test.frob; # calls the frob method of Child rather than Parent
=end code
This produces the output:
the child's somewhat more fancy frob is called
=head2 Object Construction
Objects are generally created through method calls, either on the type
object or on another object of the same type.
Class L<Mu> provides a constructor method called L<new>, which takes named
arguments and uses them to initialize public attributes.
=for code :allow<B L>
class Point {
has $.x;
has $.y = 2 * $!x;
}
my $p = PointB<.L<new>>( x L«=>» 1, y => 2);
# ^^^ inherited from class Mu
say "x: ", $p.x;
say "y: ", $p.y;
This outputs:
x: 1
y: 2
=for code :allow<B L>
my $p2 = PointB<.new>( x => 5 );
# the given value for x is used to calculate the right
# value for y.
say "x: ", $p.x;
say "y: ", $p.y;
This outputs:
x: 5
y: 10
C<Mu.new> calls method L<bless> on its invocant, passing all the named
arguments. C<bless> creates the new object and then calls method C<BUILDALL>
on it. C<BUILDALL> walks all subclasses in reverse method resolution order
(i.e. from L<Mu> to most derived classes) and in each class checks for
existence of a method named C<BUILD>. If it exists, it is called, again
passing all named arguments from method C<new> to it. If not, the public
attributes from this class are initialized from named arguments of the same
name. In either case, if neither C<BUILD> nor the default mechanism has
initialized the attribute, default values are applied (the C<2 * $!x> in the
example above).
Due to the nature of the default behavior of C<BUILDALL> and custom C<BUILD>
submethods, named arguments to the constructor C<new> derived from C<Mu> can
correspond directly to public attributes of any of the classes in the method
resolution order, or to any named parameter to any C<BUILD> submethod.
This object construction scheme has several implications for customized
constructors. First, custom C<BUILD> methods should always be submethods,
otherwise they break attribute initialization in subclasses. Second,
C<BUILD> submethods can be used to run custom code at object construction
time. They can also be used for creating aliases for attribute
initialization:
=begin code :allow<B L>
class EncodedBuffer {
has $.enc;
has $.data;
submethod B<BUILD>(:encoding(:$enc), :$data) {
$!enc L<:=> $enc;
$!data := $data;
}
}
my $b1 = EncodedBuffer.new( encoding => 'UTF-8', data => [64, 65] );
my $b2 = EncodedBuffer.new( enc => 'UTF-8', data => [64, 65] );
# both enc and encoding are allowed now
=end code
Since passing arguments to a routine binds the arguments to the parameters,
a separate binding step is unnecessary if the attribute is used as a
parameter. Hence the example above could also have been written as:
=for code :allow<B L>
submethod BUILD(:encoding(:$B<!>enc), :$B<!>data) {
# nothing to do here anymore, the signature binding
# does all the work for us.
}
The third implication is that if you want a constructor that accepts
positional arguments, you must write your own C<new> method:
=for code :allow<B L>
class Point {
has $.x;
has $.y;
method new($x, $y) {
self.L<bless>(:$x, :$y);
}
}
However this is considered poor practice, because it makes correct
initialization of objects from subclasses harder.
Another thing to note is that the name C<new> is not special in Perl 6. It
is merely a common convention. You can call C<bless> from any method at all,
or use C<CREATE> to fiddle around with low-level workings.
Another pattern of hooking into object creation is by writing your own method
C<BUILDALL>. To make sure that initialization of superclasses works fine, you
need to C<callsame> to invoke the parent classes C<BUILDALL>.
=begin code
class MyClass {
method BUILDALL(|) {
# initial things here
callsame; # call the parent classes (or default) BUILDALL
# you can do final checks here.
}
}
=end code
=comment TODO: better example for BUILDALL overriding
=head1 X<Roles|declarator,role>
Roles are in some ways similar to classes, in that they are a collection of
attributes and methods. They differ in that roles are also meant for
describing only parts of an object's behavior and in how roles are applied
to classes. Or to phrase it differently, classes are meant for managing
instances and roles are meant for managing behavior and code reuse.
=begin code :allow<B L>
role Serializable {
method serialize() {
self.L<perl>; # very primitive serialization
}
method deserialize($buf) {
L<EVAL> $buf; # reverse operation to .perl
}
}
class Point B<does> Serializable {
has $.x;
has $.y;
}
my $p = Point.new(:x(1), :y(2));
my $serialized = $p.serialize; # method provided by the role
my $clone-of-p = Point.deserialize($serialized);
say $clone-of-p.x; # 1
=end code
Roles are immutable as soon as the compiler parses the closing bracket of
the role declaration.
=head2 Z<>Role Application
Role application differs significantly from class inheritance. When a role
is applied to a class, the methods of that role are copied into the class.
If multiple roles are applied to the same class, conflicts (e.g. attributes or non-multi
methods of the same name) cause a compile-time error, which can be solved by
providing a method of the same name in the class.
This is much safer than multiple inheritance, where conflicts are never
detected by the compiler, but are instead simply resolved to the superclass
that appears earlier in the method resolution order, which might or might not be what the
programmer wanted.
For example, if you've discovered an efficient method to ride cows, and are
trying to market it as a new form of popular transportation, you might have
a class C<Bull>, for all the bulls you keep around the house, and a class
C<Automobile>, for things that you can drive.
class Bull {
has Bool $.castrated = False;
method steer {
# Turn your bull into a steer
$!castrated = True;
return self;
}
}
class Automobile {
has $.direction;
method steer ($!direction) { }
}
class Taurus is Bull is Automobile { }
my $t = Taurus.new;
$t.steer; # Castrates $t
With this setup, your poor customers will find themselves unable to turn
their Taurus and you won't be able to make more of your product! In this
case, it may have been better to use roles:
role Bull-Like {
has Bool $.castrated = False;
method steer {
# Turn your bull into a steer
$!castrated = True;
return self;
}
}
role Steerable {
has Real $.direction;
method steer (Real $d = 0) {
$!direction += $d;
}
}
class Taurus does Bull-Like does Steerable { }
This code will die with something like:
===SORRY!===
Method 'steer' must be resolved by class Taurus because it exists in
multiple roles (Steerable, Bull-Like)
This check will save you and your customers a lot of headaches and you can
simply define your class instead as:
class Taurus does Bull-Like does Steerable {
method steer ($direction?) {
self.Steerable::steer($direction?)
}
}
When a role is applied to a second role, the actual application is delayed
until the second class is applied to a class, at which point both roles are
applied to the class. Thus
role R1 {
# methods here
}
role R2 does R1 {
# methods here
}
class C does R2 { }
produces the same class C<C> as
role R1 {
# methods here
}
role R2 {
# methods here
}
class C does R1 does R2 { }
=head2 Stubs
When a role contains a stubbed method, a non-stubbed version of a method of
the same name must be supplied at the time the role is applied to a class.
This allows you to create roles that act as abstract interfaces.
=begin code :allow<B L>
role AbstractSerializable {
method serialize() { B<L<...>> } # literal ... here marks the
# method as a stub
}
# the following is a compile time error, for example
# Method 'serialize' must be implemented by Point because
# it is required by a role
class APoint does AbstractSerializable {
has $.x;
has $.y;
}
# this works:
class SPoint does AbstractSerializable {
has $.x;
has $.y;
method serialize() { "p($.x, $.y)" }
}
=end code
The implementation of the stubbed method may also be provided by another
role.
=head2 Automatic Role Punning
Any attempt to instantiate (and many other kinds of usage) a role will
automatically create a class with the same name as the role, making it
possible to transparently use a role as if it were a class.
=begin code
role Point {
has $.x;
has $.y;
method abs { sqrt($.x * $.x + $.y * $.y) }
}
say Point.new(x => 6, y => 8).abs;
=end code
We call this automatic creating of classes I<punning>, and the generated class
a I<pun>.
=head2 Parameterized Roles
Roles can be parameterized, by giving them a signature in square brackets:
=begin code
role BinaryTree[::Type] {
has BinaryTree[Type] $.left;
has BinaryTree[Type] $.right;
has Type $.node;
method visit-preorder(&cb) {
cb $.node;
for $.left, $.right -> $branch {
$branch.visit-preorder(&cb) if defined $branch;
}
}
method visit-postorder(&cb) {
for $.left, $.right -> $branch {
$branch.visit-postorder(&cb) if defined $branch;
}
cb $.node;
}
method new-from-list(::?CLASS:U: *@el) {
my $middle-index = @el.elems div 2;
my @left = @el[0 .. $middle-index - 1];
my $middle = @el[$middle-index];
my @right = @el[$middle-index + 1 .. *];
self.new(
node => $middle,
left => @left ?? self.new-from-list(@left) !! self,
right => @right ?? self.new-from-list(@right) !! self,
);
}
}
my $t = BinaryTree[Int].new-from-list(4, 5, 6);
$t.visit-preorder(&say); # 5 \n 4 \n 6
$t.visit-postorder(&say); # 4 \n 6 \n 5
=end code
Here the signature consists only of a type capture, but any signature will do:
=begin code
use v6;
enum Severity <debug info warn error critical>;
role Logging[$filehandle = $*ERR] {
method log(Severity $sev, $message) {
$filehandle.print("[{uc $sev}] $message\n");
}
}
Logging[$*OUT].log(debug, 'here we go'); # [DEBUG] here we go
=end code
You can have multiple roles of the same name, but with different signatures;
the normal rules of multi dispatch apply for choosing multi candidates.
=head1 Meta-Object Programming and Introspection
Perl 6 has a meta object system, which means that the behavior of objects,
classes, roles, grammars, enums etc. are themselves controlled by other
objects; those objects are called I<meta objects>. Meta objects are, like
ordinary objects, instances of classes, in this case we call them I<meta
classes>.
For each object or class you can get the meta object by calling C<.HOW> on
it. Note that although this looks like a method call, it is actually
special-cased in the compiler, so it is more like a macro.
So, what can you do with the meta object? For one you can check if two
objects have the same meta class by comparing them for equality:
say 1.HOW === 2.HOW; # True
say 1.HOW === Int.HOW; # True
say 1.HOW === Num.HOW; # False
Perl 6 uses the word I<HOW>, Higher Order Workings, to refer to the meta
object system. Thus it should be no surprise that in Rakudo, the class name
of the meta class that controls class behavior is called
C<Perl6::Metamodel::ClassHOW>. For each class there is one instance of
C<Perl6::Metamodel::ClassHOW>.
But of course the meta model does much more for you. For example it allows
you to introspect objects and classes. The calling convention for methods on
meta objects is to call the method on the meta object and pass in the object
of interest as first argument to the object. So to get the name of the class
of an object, you could write:
my $object = 1;
my $metaobject = 1.HOW;
say $metaobject.name($object); # Int
# or shorter:
say 1.HOW.name(1); # Int
(The motivation is that Perl 6 also wants to allow a more prototype-based
object system, where it's not necessary to create a new meta object for
every type).
To get rid of using the same object twice, there is a shortcut:
say 1.^name; # Int
# same as
say 1.HOW.name(1); # Int
See L<Metamodel::ClassHOW|/type/Metamodel::ClassHOW> for documentation of
the meta class of C<class> and also the L<general documentation on the meta
object protocol|/language/mop>.
=end pod