cloneraku

Why is the deep cloned object still linked?


Following the documentation and this SO answer I wrote the following class with clone method, but the tests in the code do not give the expected result.


use v6.d;
use Test;

class Numeration {

    has Int @!counters is default(1);
    submethod TWEAK( ) { @!counters = Nil }

    multi method Str () {
        @!counters>>.Str.join('.') ~ '.'
    }
    multi method Str ( $n ) {
        @!counters[^$n]>>.Str.join('.') ~ '.'
    }
    multi method inc (Int() $level) {
        @!counters[$level - 1]++;
        @!counters.splice($level);
        self
    }
    multi method inc () {
        self.inc(1)
    }
    method reset () {
        @!counters = Nil;
        self
    }
    method set (Int() $level, $value ) {
        @!counters[$level - 1] = $value;
        self
    }
    multi method clone {
        nextwith :counters(@!counters.clone), |%_
    }
}

my Numeration $n .= new;
$n.inc;
is $n.set(5,3).Str, '2.1.1.1.3.', 'set beyond last extent puts 1 in intermediate position';

my $m = $n.clone;
is $m.Str, '2.1.1.1.3.', 'same as n';
is $m.inc(3).Str(5), '2.1.2.1.1.', 'increments properly';
is $n.Str(5), '2.1.1.1.3.', 'incrementing m leaves n unchanged';

The last test fails.

I am not sure why.

Update: if the line

   has Int @!counters is default(1);

is changed to

   has Int @.counters is default(1);

then the final test now returns ok.

Why does adding the automatic accessor make the clone method work?


Solution

  • After discussing this with @lizmat, it seems that using nextwith inside the clone method leads to a call to new, but new only picks up public attributes (those declared with has @.counters) but not private ones (eg has @!counters).

    note the difference between '.' and '!'

    So a different approach is needed with clone, such

    
    method !set-counters(@counters) {
        @!counters := @counters;
        self
    }
    multi method clone(Numeration:D:) {
        callsame!set-counters(@!counters.clone)
    }
    

    This achieves the desired result.