Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

DeepCopy.pm - stab at a universal deep copier

0 views
Skip to first unread message

Andrew Perrin - Demography

unread,
Feb 25, 2000, 3:00:00 AM2/25/00
to
Following is a short package I wrote after being hit with the 'deep
copying' problem: if you construct complex structures by using
references, then assign them to other scalars, operations on the 'new'
versions affect the old as well:

$foo = {dates => [7,14,21],
times => [2,5,8]};
$bar = $foo;
$bar->{dates}->[0] = 2;

now:
print $foo->{dates}->[0];
2

The DeepCopy.pm package (inspired by an article I read but can't find
now in SysAdmin magazine, I think by Randal Schwartz) implements a
generic deep copier. It (tries to) create a 'fresh' copy of $foo, with
all references pointing to new data, not the same points as the old
reference. I'm posting it here and welcome any comments, critiques,
even flames. It's also on my tips page,
http://demog.berkeley.edu/~aperrin/tips . It runs fine under -w and
use strict.

Usage:
use DeepCopy;

$bar = copy $foo;

The module:

package DeepCopy;
require Exporter;
@ISA=qw/Exporter/;
@EXPORT=qw/copy/;

sub copy {
# copy $_[0] and return a freshly-reffed version.
my ($out,$bless);
my $orig = shift;
my $type = ref $orig;
return $orig unless $type;
unless ($type =~ /SCALAR|REF|CODE|ARRAY|HASH|GLOB/) {
$bless = $type;
if (UNIVERSAL::isa($orig,'SCALAR')) {
$type = 'SCALAR';
} elsif (UNIVERSAL::isa($orig,'REF')) {
$type = 'REF';
} elsif (UNIVERSAL::isa($orig,'CODE')) {
$type = 'CODE';
} elsif (UNIVERSAL::isa($orig,'ARRAY')) {
$type = 'ARRAY';
} elsif (UNIVERSAL::isa($orig,'HASH')) {
$type = 'HASH';
} elsif (UNIVERSAL::isa($orig,'GLOB')) {
$type = 'GLOB';
} else {
warn 'I am now deeply lost.';
return $orig;
}
}
if ($type eq 'SCALAR' or
$type eq 'REF' or
$type eq 'CODE') {
my $foo = $orig;
$out = \$foo;
} elsif ($type eq 'ARRAY') {
push @$out, copy($_) for @$orig;
} elsif ($type eq 'HASH') {
$out->{$_} = copy($orig->{$_}) for keys %$orig;
} elsif ($type eq 'GLOB') {
warn 'GLOB copy unimplemented';
my $foo = $orig;
$out = \$foo;
} else {
warn 'I am now deeply lost.';
}
bless $out, $bless if $bless;
return $out;
}

1;

--
---------------------------------------------------------------------
Andrew J. Perrin - ape...@demog.berkeley.edu - NT/Unix Admin/Support
Department of Demography - University of California at Berkeley
2232 Piedmont Avenue #2120 - Berkeley, California, 94720-2120 USA
http://demog.berkeley.edu/~aperrin --------------------------SEIU1199

Jean-Louis Leroy

unread,
Feb 26, 2000, 3:00:00 AM2/26/00
to
> } else {
> warn 'I am now deeply lost.';
> }

You could lookup up a global hash that would contain extra copy
methods. Modules like Set::Object (which stores elements outside
script space) could register themselves with DeepCopy. The result
would be an extensible system.

--

V
VLR Jean-Louis Leroy
F http://users.skynet.be/jll

Ilya Zakharevich

unread,
Feb 26, 2000, 3:00:00 AM2/26/00
to
[A complimentary Cc of this posting was sent to Andrew Perrin - Demography
<ape...@famine.DEMOG.Berkeley.EDU>],
who wrote in article <u5k1z60...@famine.DEMOG.Berkeley.EDU>:

> Following is a short package I wrote after being hit with the 'deep
> copying' problem: if you construct complex structures by using
> references, then assign them to other scalars, operations on the 'new'
> versions affect the old as well:

Use serialization/deserialization instead. See the docs of any
serialization module (FreezeThaw/Storable etc).

> use DeepCopy;
>
> $bar = copy $foo;

$foo = \$foo;
$bar = copy $foo;

Believe me, you do *not* want to reinvent *this* particular bicycle.

Ilya

0 new messages