RFC 67 (v3) 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: 29 Aug 2000
Mailing List: [email protected]
Version: 3
Number: 67
Status: Frozen
=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).