kcott has asked for the wisdom of the Perl Monks concerning the following question:
I seem to recall seeing somewhere a clone() method for Moose objects.
I've looked in Moose
and Moose::Manual::Construction
but don't see anything like this.
I've also had a poke around in Super Search but have found nothing promising.
In my current code, I writing this type of thing:
my $cloned_object = ref($existing_object)->new();
This works fine for what I'm working on at the moment
because the classes in question have no required attributes
and taking the defaults is exactly what I want in this instance.
I don't have any requirement to do anything different at the moment;
however, it occurs to me that I might do in the future,
perhaps something like:
my $cloned_object = ref($object)->new(%objects_attrs_and_values);
which might be better as something like:
my $cloned_object = $existing_object->clone();
So, is there such a thing as clone() or did I just imagine it?
If it exists, please point me to documentation;
if not, any related thoughts on this are welcome.
Re: Moose 'clone' Constructor
by Arunbear (Prior) on Jul 04, 2018 at 09:54 UTC
|
my $cloned_object = $existing_object->meta->clone_object($existing_obj
+ect);
| [reply] [d/l] |
|
G'day Arunbear,
++
What can I say: great minds link alike. :-)
When I got home from work, Corion's reply was the only response at that time.
I followed the link he'd provided, followed some more links from that, then hit "reply".
As I was composing, I noticed I now had a reply from you and thought: "Oh good, more information, I'll look at that in a minute."
— and when I did, I then thought: "Hmmm, that looks familiar."
Anyway, I've only just found it, perhaps you've used it.
I noticed there's an additional argument:
$metaclass->clone_object($instance, %params)
Is %params as straightforward as it seems?
I'm thinking maybe issues with values that are references to data structures,
as opposed to simpler (Str, Int, etc.) values.
| [reply] [d/l] [select] |
|
%params are the same kind of data as were passed to the constructor when $existing_object was created (but now you have a chance to override those if needed).
| [reply] [d/l] [select] |
|
Re: Moose 'clone' Constructor
by choroba (Cardinal) on Jul 04, 2018 at 12:49 UTC
|
Note that there can't be a general cloning routine free to use in all the cases. Imagine each object has a temp file created somewhere - when cloning an object, do you want it to share the same file(handle)? What if each object registers itself to a static hash or a parent object, generates a unique ID, seeds a PRNG, etc?
#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
{ package MyObj;
use Moose;
has fh => (is => 'ro', builder => '_build_fh');
sub _build_fh {
my ($self) = @_;
open my $fh, '>', "/tmp/$self" or die $!;
return $fh
}
sub DEMOLISH {
my ($self) = @_;
close $self->fh;
unlink "/tmp/$self";
}
}
my $o = 'MyObj'->new;
{
my $c = $o->meta->clone_object($o);
}
say { $o->fh } "Hello world!"; # say() on closed filehandle $fh
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] [select] |
|
my $cloned_object = ref($existing_object)->new();
As I indicated in the OP, I want an object that's of the same class as $existing_object,
but I want default values (not whatever values $existing_object has).
In fact, if I had taken $existing_object's values,
that would've broken my code in all sorts of interesting ways.
| [reply] [d/l] [select] |
Re: Moose 'clone' Constructor
by Corion (Patriarch) on Jul 04, 2018 at 07:56 UTC
|
I see MooseX::Clone, which implements more cloning support, but alludes to some bare-bones cloning support in Moose. If I read the discussion right, cloning in Moose is just:
bless { %$old }, ref $old;
... but I don't know if there is a default constructor ->clone() provided. | [reply] [d/l] [select] |
|
G'day Corion,
++ Thanks for that.
MooseX::Clone looks interesting.
Its abstract does say "Fine-grained cloning support",
and it looks like there could be a fair bit of work setting this up.
Perhaps useful in situations where specific custom cloning was wanted.
I also note a TODO section: I tend to be a bit wary of those
as it suggests incomplete functionality
— might wait for that to become TODONE. :-)
With a bit of link-hopping from there, I came across
"Class::MOP::Class - Object instance construction and cloning".
The clone_object() method appears less fine-grained (than MooseX::Clone)
and perhaps more useful as a general solution.
Both of those have example code for setting up a clone() method in your own class.
As I said in the OP, not an immediate requirement but I'll keep both of those in mind.
Thanks again.
| [reply] [d/l] [select] |
Re: Moose 'clone' Constructor
by tobyink (Canon) on Jul 04, 2018 at 16:32 UTC
|
Others have already pointed out how you can use the metaobject protocol to clone objects with Moose. If you know that the object in question is a Moose object, this is a reasonable solution. I want to mention my module Object::Util though. It contains a bunch of utility methods which can be used with Moose objects and other objects too.
use Object::Util;
my $cloned_object = $existing_object->$_clone(%extra_parameters);
Object::Util will first check if the existing object has a clone method, and if so, will just call that. After that, it falls back to using the metaobject protocol if it detects the object is Moose- or Mouse-based. Finally as a last resort, if the object is a blessed hashref, it simply does a shallow copy of the hashref and blesses the new hashref.
Object::Util has a bunch of other cool things too, like:
$cloned_object->$_extend({
my_new_method => sub {
my $self = shift;
print "yay!\n";
},
});
$cloned_object->my_new_method(); # says "yay!"
Note that the methods provided by Object::Util are coderefs in scalar variables, so you call $object->$_method() instead of $object->method(). This is a way to make the methods available for all objects of all classes without polluting UNIVERSAL.
| [reply] [d/l] [select] |
|
G'day tobyink,
++
Thanks for pointing me to that module: I hadn't encountered it previously.
I found the way you've used coderefs interesting.
I suspect I may have seen something similar in the past but probably wasn't paying close enough attention.
I'm certainly familiar with:
$ perl -E 'my $x = sub { say "@_" }; $x->("fred")'
fred
And, as expected, this didn't work:
$ perl -E 'my $x = sub { say "@_" }; $x("fred")'
syntax error at -e line 1, near "$x("
Execution of -e aborted due to compilation errors.
However, I've never written code like:
$ perl -E 'my $x = sub { say "@_" }; "XYZ"->$x("fred")'
XYZ fred
I'll have to look into that further.
I've read the "Object::Util - Rationale" section.
Can you point me to any documentation that explains this in more detail?
| [reply] [d/l] [select] |
|
| [reply] |
|
|
|
perl -E 'my $x = sub { say "@_" }; &$x("fred")'
as to
"XYZ"->$x("fred"),
I would not have expected it to work, becuase "XYZ" is not blessed to anything,
but seeing that it does, it behaves like i expected, with
$thing->method($arg)
calling &method as method($thing,$arg)
| [reply] [d/l] [select] |
|
|
|
|
|