RFC 67 (v2) Deep Copying, aka, cloning around.

[email protected] (Perl6 RFC Librarian)
Newsgroups perl.perl6.language,perl.perl6.announce
Message-ID <[email protected]>
This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

Deep Copying, aka, cloning around.

=head1 VERSION

     Maintainer: Peter Scott <[email protected]>
     Date: 8 Aug 2000
     Last-Modified: 12 Aug 2000
     Version: 2
     Mailing List: [email protected]
     Number: 67

=head1 ABSTRACT

Perl should have a C<clone> method for deep copying of hierarchical data 
structures.

Damian Conway mooted a C<clone> function for deep copying of objects as 
part of an earlier discussion.  This RFC expands upon that and gives it 
special attention.  I expect several iterations of this RFC from feedback.

=head1 DESCRIPTION

The language interface is the C<clone> method which takes an object as 
argument and returns a copy of it as result:

=over 4

=item clone SCALAR

=item clone SCALAR, CALLBACK

     $copy = clone($obj)

     $copy = clone($obj, sub { die 'Filehandle copying not allowed' })

The C<CALLBACK> is an optional function to be called if C<clone> encounters 
a filehandle, dirhandle, or object with magic or an XS implementation.  It 
will either throw an exception or return a value to be used as the cloned 
filehandle.

=back

=head1 IMPLEMENTATION

=head2 Default

The default functionality will switch on C<ref SCALAR> and recursively 
create new data structures in the way many people have written 
themselves.  Here, for instance, is Garrett Goebel 
(C<[email protected]>)'s version implementing circular reference checking:

     our %SEEN = ();
     our $DEPTH = 0;
     sub clone { # Dereference and return a deep copy of whatever's passed
         our %SEEN;
         local $_ = ref($_[0]) or return $_[0];
         exists $SEEN{$_} and return $SEEN{$_};
         $DEPTH++;

         my $rval =
           /^HASH$/   ? {map {clone($_)} (%{$_[0]})}
         : /^ARRAY$/  ? [map {clone($_)} @{$_[0]} ]
         : /^SCALAR$/ ? \${$_[0]}
         : /^FORMAT$/ ? $_[0] # Shallow copy until we figure out
         : /^Regexp$/ ? $_[0] # B.pm and Class::Tom show the way
         : /^REF$/    ? $_[0] # how to deep copy these. Note:
         : /^IO$/     ? $_[0] # "
         : /^GLOB$/   ? $_[0] # "
         : /^CODE$/   ? $_[0] # " (B::Deparse)
         : $_[0]->CLONE;

         --$DEPTH
         and $SEEN{$_} = $rval
         or %SEEN = ();
         $rval;
     }


=head2 Blessed objects

If C<clone> encounters a blessed object C<$obj> say, it will call
C<$obj->CLONE(CALLBACK)>.  If the C<CLONE> method is not defined in 
C<$obj>'s class or any of its superclasses, C<UNIVERSAL::CLONE> will carry 
out the default functionality on the internal representation of 
C<$obj>.  Probably this will mean little more than calling C<clone>.

Classes (e.g., DBI) may well choose to throw an exception in their C<CLONE> 
methods.

=head2 Filehandles

If C<clone> encounters an C<IO::Handle>, its default behavior will be to 
make a copy of the filehandle (debatable: perhaps the default should be to 
throw an exception) unless a C<CALLBACK> function was specified, in which 
case it will use the return value of C<CALLBACK>.

=head2 Tied variables

If C<clone> encounters a tied variable, it will call the C<CLONE> method in 
the class of the underlying implementation object or fall back to 
C<UNIVERSAL::CLONE>.  (Note: perhaps all missing functions from tied 
classes should punt to C<UNIVERSAL>.  But that is outside the scope of this 
RFC.)

=head2 Cyclic references

The C<clone> function should detect circular references and replicate the 
same structure in the copy.  One implementation that suggests itself is to 
keep a hash of input references with output references as values.  It has 
been suggested that the code to do this will already be available in the 
garbage collector.

=head2 Exceptions

If an exception is thrown anywhere during the copying, it needs to be 
trapped so that C<clone> can clean up any cyclic references it has created, 
then rethrown.

=head1 REFERENCES

The L<Storable> module (http://search.cpan.org/doc/RAM/Storable-0.7.0/Storable.pm).

The L<Data::Dumper> module (http://search.cpan.org/doc/GSAR/perl-5.6.0/ext/Data/Dumper/Dumper.pm).
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.