[% setvar title Deep Copying, aka, cloning around. %]

This file is part of the Perl 6 Archive

Note: these documents may be out of date. Do not use as reference!

To see what is currently happening visit http://www.perl6.org/

TITLE

Deep Copying, aka, cloning around.

VERSION

  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

ABSTRACT

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.

DESCRIPTION

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

IMPLEMENTATION

Default

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;
      }

Blessed objects

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.

Filehandles

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.

Tied variables

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.)

Cyclic references

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.

Exceptions

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.

REFERENCES

The Storable module (search.cpan.org

The Data::Dumper module (search.cpan.org