[% setvar title Deep Copying, aka, cloning around. %]
Note: these documents may be out of date. Do not use as reference! |
To see what is currently happening visit http://www.perl6.org/
Deep Copying, aka, cloning around.
Maintainer: Peter Scott <peter@psdt.com> Date: 8 Aug 2000 Last Modified: 29 Aug 2000 Mailing List: perl6-language@perl.org Number: 67 Version: 3 Status: Frozen
Perl should have a clone
method for deep copying of hierarchical data
structures.
Damian Conway mooted a 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.
The language interface is the clone
method which takes an object as
argument and returns a copy of it as result:
$copy = clone($obj) $copy = clone($obj, sub { die 'Filehandle copying not allowed' })
The CALLBACK
is an optional function to be called if 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.
The default functionality will switch on ref SCALAR
and recursively
create new data structures in the way many people have written
themselves. Here, for instance, is Garrett Goebel
(garrett@scriptpro.com
)'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; }
If clone
encounters a blessed object $obj
say, it will call
$obj-
CLONE(CALLBACK)>. If the CLONE
method is not defined in
$obj
's class or any of its superclasses, UNIVERSAL::CLONE
will carry
out the default functionality on the internal representation of
$obj
. Probably this will mean little more than calling clone
.
Classes (e.g., DBI) may well choose to throw an exception in their CLONE
methods.
If clone
encounters an 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 CALLBACK
function was specified, in which
case it will use the return value of CALLBACK
.
If clone
encounters a tied variable, it will call the CLONE
method in
the class of the underlying implementation object or fall back to
UNIVERSAL::CLONE
. (Note: perhaps all missing functions from tied
classes should punt to UNIVERSAL
. But that is outside the scope of this
RFC.)
The 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.
If an exception is thrown anywhere during the copying, it needs to be
trapped so that clone
can clean up any cyclic references it has created,
then rethrown.
The Storable module (search.cpan.org
The Data::Dumper module (search.cpan.org