Skip to content

Commit fb2d3fc

Browse files
committed
Improve object clonning docs
- Document clone behaviour of %. and @. attributes (Closes #1458) - Shorten wording - Move custom clone examples to Mu.clone docs - Mention private attrs get cloned too - Remove "magical"; we don't have any magic - Remove incorrect and somewhat rambly paragraph about Mu.clone being a submethod… it isn't
1 parent 5ede23f commit fb2d3fc

File tree

2 files changed

+71
-42
lines changed

2 files changed

+71
-42
lines changed

doc/Language/objects.pod6

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -524,47 +524,25 @@ say RectangleWithCachedArea.new( x2 => 5, x1 => 1, y2 => 1, y1 => 0).area;
524524
525525
=head2 Object Cloning
526526
527-
The C<Mu> parent class, from which all classes inherit, supplies a
528-
method named L<clone>, which is somewhat magical in that it can copy
529-
values from an object's private attributes to create a new object.
530-
This cloning is shallow since it only binds attributes to
531-
the same values contained in the original object; it does
532-
not make copies of those values.
533-
534-
As with C<new>, public attributes can be set to initial values.
535-
These override values received from the original object. (See
536-
the documentation for Mu's L<clone> for an example.)
537-
538-
Note that since C<clone> is not a C<submethod>, a class which provides
539-
its own C<clone> method will replace the C<Mu> method. There is no
540-
automatic mechanism like C<BUILDALL> for cloning. For example, if one
541-
wished to make clone deeper for a particular class, one would will
542-
probably want to use C<callwith> or C<nextwith> to push the deeper
543-
copies to superclasses:
544-
545-
class A {
546-
has $.a;
547-
#...
548-
method clone {
549-
nextwith(:a($.a.clone))
550-
}
551-
}
527+
The cloning is done using L<clone> method available on all objects, which
528+
shallow-clones both public and private attributes. New values for I<public>
529+
attributes can be supplied as named arguments.
552530
553-
This works well for simple classes, but in some cases one might need
554-
to follow C<BUILDALL>'s lead and work in reverse method resolution
555-
order:
531+
=begin code
532+
class Foo {
533+
has $.foo = 42;
534+
has $.bar = 100;
535+
}
556536
557-
=begin code :preamble<class A {};>
558-
class B is A {
559-
has $.b;
560-
#...
561-
method clone {
562-
my $obj = callsame;
563-
$obj.b = $!b.clone(:seed($obj.a.generate_seed));
564-
$obj
565-
}
566-
}
567-
=end code
537+
my $o1 = Foo.new;
538+
my $o2 = $o1.clone: :bar(5000);
539+
say $o1; # Foo.new(foo => 42, bar => 100)
540+
say $o2; # Foo.new(foo => 42, bar => 5000)
541+
=end code
542+
543+
See L«documentation for C<Mu.clone>|/routine/clone» for details on how
544+
non-scalar attributes get cloned, as well as examples of implementing your
545+
own custom clone methods.
568546
569547
=head1 X<Roles|declarator,role>
570548

doc/Type/Mu.pod6

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,9 @@ Returns the object it is called on.
162162
163163
method clone(*%twiddles)
164164
165-
Creates a shallow clone of the invocant. Alternative values for I<public>
166-
attributes can be provided via named arguments with names matching the
167-
attributes' names.
165+
Creates a shallow clone of the invocant, including shallow cloning of private
166+
attributes. Alternative values for I<public> attributes can be provided via
167+
named arguments with names matching the attributes' names.
168168
169169
=begin code
170170
class Point2D {
@@ -180,6 +180,57 @@ say $p; # OUTPUT: «Point(2, 3)␤»
180180
say $p.clone(y => -5); # OUTPUT: «Point(2, -5)␤»
181181
=end code
182182
183+
Note that C<.clone> does not go the extra mile to shallow-copy C<@.> and C<%.>
184+
sigiled attributes and, if modified, the modifications will still be available
185+
in the original object:
186+
187+
=begin code
188+
class Foo {
189+
has $.foo is rw = 42;
190+
has &.boo is rw = { say "Hi" };
191+
has @.bar = <a b>;
192+
has %.baz = <a b c d>;
193+
}
194+
195+
my $o1 = Foo.new;
196+
with my $o2 = $o1.clone {
197+
.foo = 70;
198+
.bar = <Z Y>;
199+
.baz = <Z Y X W>;
200+
.boo = { say "Bye" };
201+
}
202+
203+
# Hash and Array attribute modifications in clone appear in original as well:
204+
say $o1; # OUTPUT: «Foo.new(foo => 42, bar => ["Z", "Y"], baz => {:X("W"), :Z("Y")}, …␤»
205+
say $o2; # OUTPUT: «Foo.new(foo => 70, bar => ["Z", "Y"], baz => {:X("W"), :Z("Y")}, …␤»
206+
$o1.boo.(); # OUTPUT: «Hi␤»
207+
$o2.boo.(); # OUTPUT: «Bye␤»
208+
=end code
209+
210+
To clone those, you could implement your own C<.clone> that clones the
211+
appropriate attributes and passes the new values to C<Mu.clone>, for example,
212+
via L<nextwith>. Alternatively, your own C<.clone> could clone self first
213+
(using C<self.Mu::clone> or L<callsame>) and then manipulate the clone as needed,
214+
before returning it.
215+
216+
=begin code
217+
class Bar {
218+
has @.foo = <a b>;
219+
has %.bar = <a b c d>;
220+
method clone { nextwith :foo(@!foo.clone) :bar(%!bar.clone) }
221+
}
222+
223+
my $o1 = Bar.new;
224+
with my $o2 = $o1.clone {
225+
.foo = <Z Y>;
226+
.bar = <Z Y X W>;
227+
}
228+
229+
# Hash and Array attribute modifications in clone do not affect original:
230+
say $o1; # OUTPUT: «Bar.new(foo => ["a", "b"], bar => {:a("b"), :c("d")})␤»
231+
say $o2; # OUTPUT: «Bar.new(foo => ["Z", "Y"], bar => {:X("W"), :Z("Y")})␤»
232+
=end code
233+
183234
=head2 method new
184235
185236
multi method new(*%attrinit)

0 commit comments

Comments
 (0)