Convert a Moose Object into a Subtype
Date: 03 June 2011
Have you ever had the situation where you had a parent class but you find out later in the code that you really want a subclass? With perl Moose, it’s really easy to do.
Consider the classic point example described in Moose::Cookbook::Basics::Recipe1. Suppose I start with a Point but I decide later that I need that point to shift into 3D. I don’t want to change the values for x and y, I just want to add the new z point. I could brute force it by creating a new point and copying the values over from the old point but that feels like more work than it should be. Well, it is.
Fortunately, Moose uses Class::MOP::Class which provides the rebless_instance method which can convert a object into a subtype.
package Point;
use Moose;
has 'x' => (isa => 'Int', is => 'rw');
has 'y' => (isa => 'Int', is => 'rw');
package Point3D;
use Moose;
extends 'Point';
has 'z' => (isa => 'Int', is => 'rw');
package main;
use Data::Dumper;
my $p1 = Point->new(x => 4, y => 3);
print Dumper $p1;
$p1 = Point3D->meta->rebless_instance($p1);
print Dumper $p1;
And the output:
$VAR1 = bless( {
'y' => 3,
'x' => 4
}, 'Point' );
$VAR1 = bless( {
'y' => 3,
'x' => 4
}, 'Point3D' );
Now $p1
is a Point3D object rather than a Point object.
You can go backwards, too, with the rebless_instance_back
method but you face
the potential for data loss when you do that.