Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moose (Perl): Is it okay to use %$object to get the data representation of an object for serialization?

I frequently use Moose to make sure my data have suitable default values, like here:

package Bla;
use Moose;
has eins => is => 'ro', isa => 'Int';
has zwei => is => 'ro', isa => 'Int', default => 2;
no Moose; __PACKAGE__->meta->make_immutable;

package main;
use v5.10;
use Data::Dumper;
use URI;

my $bla = Bla->new( eins => 77 );
my $bl2 = Bla->new;
print Dumper $bla, $bl2;
say join "\t", %$bla;
say join "\t", %$bl2;

my $u = URI->new( 'http://www.example.com/ws' );
$u->query_form( %$bla );
say $u;
$u->query_form( %$bl2 );
say $u;

As long as that kind of data container doesn't have any reference members (hence no nesting), would you say it is okay, or recommendable, to just use the object hashtable as in %$object if you want to get at the raw data, let's say as initializer for serialization via URI->query_form or similar methods? Or is there a better way to achieve this that's built into Moose?

UPDATE

Looks like I've been leading people on the wrong tracks by dropping the little word serialization in the lines above, and in the title, and even in the tags. Note that I'm not interested in finding serializers. In my example, the URI module is the serializer. The question is how to get at the data to feed URI->query_form (or any other serializer I might try). So what I want to know is whether for a given Moose object $object it is okay to grab the data (keys and values, or, if you prefer, property names and values) by just dereferencing the object reference, as in %$object? This will work, if my experience hitherto collected is anything to go by, as long as the objects don't contain any reference values (like array references, other objects, etc) and - the thing I'm not sure about - Moose won't use the instance reference to store data of its own, like __MOOSE_WHATNOT => $funky_moose_addon. So might Moose use the instance reference to store some of its own data, or is that precluded by design?

UPDATE 2

To answer the question in the title:

No, it's not okay to use %$object to get at the data of a Moose object, even if it doesn't contain any reference values so you'd get a copy of the strings and numbers that make up the $object. It's not okay because it breaks encapsulation. It might even result in a runtime error because although the hash is the default data structure to form the base of a Moose object, there is no guarantee that it will always be a hash, and it might in fact be something else.

You should use MooseX::Storage instead, which will provide the object with a pack method.

like image 220
Lumi Avatar asked Dec 28 '22 19:12

Lumi


2 Answers

As jira has said the canonical way would be to use MooseX::Storage. The problem with %$object is that while the default storage for a Moose object instance is a blessed hash, Moose makes no formal promises that this is always the case. MooseX::GlobRef, MooseX::NonMoose, MooseX::InsideOut for example all allow for alterative instance structures.

A package like MooseX::Storage uses the MOP to interrogate the instance meta-object and serialize the data structure properly. You can of course do this by hand by crawling the Moose::Meta::Class that is behind every Moose object, but honestly MooseX::Storage is well written and very stable at this point.

The standard usage would be:

package Class {
     use Moose;
     use MooseX::Storage;
     with Storage();
     ...
}

my $o = Class->new(...)
my $u = URI->new( 'http://www.example.com/ws' );
$u->query_form( $o->pack );
like image 147
perigrin Avatar answered Dec 30 '22 07:12

perigrin


Moose "native" way would be to use MooseX::Storage set of classes.

like image 31
jira Avatar answered Dec 30 '22 08:12

jira