Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Perl Misc (http://www.velocityreviews.com/forums/f67-perl-misc.html)
-   -   How to copy an object created by fields::new (http://www.velocityreviews.com/forums/t897436-how-to-copy-an-object-created-by-fields-new.html)

Mintcake 04-12-2006 10:49 AM

How to copy an object created by fields::new
 
What is the best way to make a copy (not a deep copy) of an object
created by fields::new?

My complete example program is below.

+++++++++++++++++++++++++++++++++++++++++
#!/usr/local/bin/perl -wl

use strict;

package Ftest;

use fields qw(foo bar xyzzy);

sub new
{
my $class = shift;
my __PACKAGE__ $self = fields::new($class);
@$self{qw(foo bar xyzzy)} = @_;
return $self;
}

package main;

my Ftest $f = new Ftest 1,2,3;
my Ftest $g = new Ftest;

@$g = @$f;
---------------------------------------------------------------------------------
The last line above does the actual copy. This version works with 5.8
as the fields implementation uses pseudo-hashes but it doesn't work
with 5.9 because of course they are not array references. If I change
it to...

%$g = %$f

.... then it works on both Perls but I get a warning about pseudo-hashes
being deprecated on the 5.8 version.

I am reluctant to include a no warnings 'deprecated'; statement. There
is a good reason for this: One of the mistakes I frequently make, when
declaring a scalar and assigning to it a reference to such an object,
is to forget the type, i.e.

my $foo = shift;

instead of

my Type $foo = shift;

The warning about deprecated pseudio-hashes catches this which I find
very useful.

I particularly want my code to work with both 5.8 and 5.10 (when it
arrives) and I don't want to put conditional code in there.


Anno Siegel 04-12-2006 04:59 PM

Re: How to copy an object created by fields::new
 
Mintcake <tony@skelding.co.uk> wrote in comp.lang.perl.misc:
> What is the best way to make a copy (not a deep copy) of an object
> created by fields::new?
>
> My complete example program is below.
>
> +++++++++++++++++++++++++++++++++++++++++
> #!/usr/local/bin/perl -wl
>
> use strict;
>
> package Ftest;
>
> use fields qw(foo bar xyzzy);
>
> sub new
> {
> my $class = shift;
> my __PACKAGE__ $self = fields::new($class);


I'd write that

my __PACKAGE__ $self = $class->fields::new;

so that fields::new is visibly called as a class method.

> @$self{qw(foo bar xyzzy)} = @_;
> return $self;
> }
>
> package main;
>
> my Ftest $f = new Ftest 1,2,3;
> my Ftest $g = new Ftest;
>
> @$g = @$f;
> ---------------------------------------------------------------------------------
> The last line above does the actual copy. This version works with 5.8
> as the fields implementation uses pseudo-hashes but it doesn't work
> with 5.9 because of course they are not array references. If I change
> it to...
>
> %$g = %$f
>
> ... then it works on both Perls but I get a warning about pseudo-hashes
> being deprecated on the 5.8 version.


I don't see the warning with neither 5.8.7 nor 5.9.4, but I'll pretend
it's there.

> I am reluctant to include a no warnings 'deprecated'; statement. There
> is a good reason for this: One of the mistakes I frequently make, when
> declaring a scalar and assigning to it a reference to such an object,
> is to forget the type, i.e.
>
> my $foo = shift;
>
> instead of
>
> my Type $foo = shift;
>
> The warning about deprecated pseudio-hashes catches this which I find
> very useful.


Then isolate the copy process to a small scope and switch off the warning
only there. Objects should be treated as opaque entities anyhow, so
accessing them as arrays or hashes outside their class is a no-no.
Instead, add a method ("clone", say) to class Ftest:

sub clone {
my $self = shift;
my __PACKAGE__ $clone = ref( $self)->fields::new;
no warnings 'deprecated';
%$clone = %$self;
$clone;
}

Instead of saying

%$g = %$f;

use

my $g = $f->clone;

The "deprecated" warning won't appear with clone(), but will be active for
the rest of your code.

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.

Mintcake 04-13-2006 10:27 AM

Re: How to copy an object created by fields::new
 

Anno Siegel wrote:
> Mintcake <tony@skelding.co.uk> wrote in comp.lang.perl.misc:
> > What is the best way to make a copy (not a deep copy) of an object
> > created by fields::new?
> >
> > My complete example program is below.
> >
> > +++++++++++++++++++++++++++++++++++++++++
> > #!/usr/local/bin/perl -wl
> >
> > use strict;
> >
> > package Ftest;
> >
> > use fields qw(foo bar xyzzy);
> >
> > sub new
> > {
> > my $class = shift;
> > my __PACKAGE__ $self = fields::new($class);

>
> I'd write that
>
> my __PACKAGE__ $self = $class->fields::new;
>
> so that fields::new is visibly called as a class method.
>

I agree - much nicer
> > @$self{qw(foo bar xyzzy)} = @_;
> > return $self;
> > }
> >
> > package main;
> >
> > my Ftest $f = new Ftest 1,2,3;
> > my Ftest $g = new Ftest;
> >
> > @$g = @$f;
> > ---------------------------------------------------------------------------------
> > The last line above does the actual copy. This version works with 5.8
> > as the fields implementation uses pseudo-hashes but it doesn't work
> > with 5.9 because of course they are not array references. If I change
> > it to...
> >
> > %$g = %$f
> >
> > ... then it works on both Perls but I get a warning about pseudo-hashes
> > being deprecated on the 5.8 version.

>
> I don't see the warning with neither 5.8.7 nor 5.9.4, but I'll pretend
> it's there.


It's there in 5.8.0 but not in 5.8.7. This suggests that the warning
issued under these circumstances was deemed to be erroneous. There are
a couple of other situations where this warning used to be issued but
is no longer, e.g.

keys %$g
values %$g
$g->{$key}

>
> > I am reluctant to include a no warnings 'deprecated'; statement. There
> > is a good reason for this: One of the mistakes I frequently make, when
> > declaring a scalar and assigning to it a reference to such an object,
> > is to forget the type, i.e.
> >
> > my $foo = shift;
> >
> > instead of
> >
> > my Type $foo = shift;
> >
> > The warning about deprecated pseudio-hashes catches this which I find
> > very useful.

>
> Then isolate the copy process to a small scope and switch off the warning
> only there. Objects should be treated as opaque entities anyhow, so
> accessing them as arrays or hashes outside their class is a no-no.
> Instead, add a method ("clone", say) to class Ftest:
>
> sub clone {
> my $self = shift;
> my __PACKAGE__ $clone = ref( $self)->fields::new;
> no warnings 'deprecated';
> %$clone = %$self;
> $clone;
> }
>
> Instead of saying
>
> %$g = %$f;
>
> use
>
> my $g = $f->clone;
>
> The "deprecated" warning won't appear with clone(), but will be active for
> the rest of your code.

I know I called them objects in the original post but they're not
really. What I really wanted were restricted hashes with the added
benefit of compile time key checking. I wanted to let users manipulate
them as if they were hashes rather than hiding anything behind a method
interface (other than the constructor of course)

Incidentally, in your solution, the temporary lexical $clone is 'typed'
but the $g scalar is not. It should be the other way around. There is
no benefit in compile time key checking when no keys appear in the
code.
>
> Anno
> --
> If you want to post a followup via groups.google.com, don't use
> the broken "Reply" link at the bottom of the article. Click on
> "show options" at the top of the article, then click on the
> "Reply" at the bottom of the article headers.




All times are GMT. The time now is 02:45 AM.

Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57