Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a separate copy of an object in Perl 6?

I don't fully understand the docs, so I've tried clone, and it seems if there is an attribute of a mutable class, it can be changed in the new object using the old one (and that's what I don't want). How to make them (i.e. the copy and the original) fully separate?

class A {
  has @.a;
}

my A $x = A.new;
my A $y = A.new;

$x.a = 1, 2;

$y = $x.clone;

$x.a.push(4);
say $y.a; # [1 2 4]
like image 373
Eugene Barsky Avatar asked Apr 27 '18 20:04

Eugene Barsky


1 Answers

The default clone inherited from Mu is shallow, as documented. This means that it will only copy the object itself, but not anything the object references. It is possible to override clone to have your preferred semantics, which is probably the best thing to do here.

One useful thing to know in doing this is that clone takes named parameters and uses them to assign to properties of the cloned object. This is worth knowing because:

  • One should make sure to handle this when overriding clone, to avoid surprises to users of the overridden clone method who use this feature
  • One can use this when overriding clone to succinctly opt in to cloning of a particular array or hash attribute

Thus for the case in the question, writing:

class A {
    has @.a;
    method clone() {
        callwith(:@!a, |%_)
    }
}

Will result in the output [1 2] as presumably desired. How does it work?

  • The |%_ just passes on any tweaks the caller of this clone method specified
  • :@!a is short for a => @!a
  • callwith calls the inherited clone (from Mu in this case)
  • Assignment, not binding, semantics are used on @!a in the target object (just as during object construction), resulting in a copy of the array

This shortcut works for hash attributes too. For an attribute containing another object, it'd look like callsame(x => $!x.clone).

like image 139
Jonathan Worthington Avatar answered Oct 21 '22 01:10

Jonathan Worthington