Seeking facts and opinion about "Class::Unbless"

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View

I've had an itch: Being able to send my plain-old-perl objects over JSON.  

So now, inspired by MooseX::Storage, I've created Class::Unbless ( ), that on request exports "unbless" and "rebless".

"unbless" turns

        bless { key => "value" }, "ModuleA";
        bless [ "val1", "val2" ], "ModuleB";


        { __class__ => 'ModuleA', key => "value" }
        [ "__class__", 'ModuleB', "val1", "val2" ]

And on the other side, "rebless" does the opposite so you get the real classes.  
I'm sure you get the idea. Conversion can be customized with "TO_UNBLESSED" and "TO_BLESSED" methods. Details, caveats, references, etc. are found in [1].

perldoc perlnewmod says:

Quoted text here. Click to load it

And so I'm asking:

1) Do you know of any other module that does this for random classes? ( I don't think it already exists )
2) What is right place in the perl module hierarchy to put this? Class::? Data::Structure::? Somewhere else?

Any other opinions?

I'd just like to ask before I submit to CPAN.


Re: Seeking facts and opinion about "Class::Unbless"

Quoted text here. Click to load it

Any reference can be blessed into a package to turn it into an object
instance. At least references to scalars can also be serialized. I also
don't think storing the package name  inline in this way is a good idea:
Why not create a hash (or an array) looking like this:

    class => 'TheClass',
        obj => ... }

A remark on the code: You're using a loop like this

foreach my $key (keys %$hash) {
    my $val = $hash->;
    my $newVal = _unbless($val, $options);
    if ($newVal) {
        $hash-> = $newVal;

in order to unbless a hash recusively (and one iterating over array
indices for arrays). The foreach-for aliases it's loop variable to the
elements on this list so this can also be written (untested) as

for (values(%$hash)) {
    my $nv = _unbless($_, $options);
    $_ = $nv if $nv;

The array loop can be rewritten using

for (@$array) {

in a similar way.

Re: Seeking facts and opinion about "Class::Unbless"

Quoted text here. Click to load it


Quoted text here. Click to load it

This idea is also easily extendable. For instance, computers don't care
if metadata markers are human readable: Turn any blessed datum in a
tripel (represented as array) whose first value is
X19zdGFydF9jbGFzc19fCg (__start_class__ base64-encoded), followed by the
class name, followed by the 'plain' data representation.  A triple of
this form in the actual input could be represented by wrapping it into
another triple with an undef class name. This would make the encoding
'universal' (for want of a better term): Provided it is known that the
received data was encoded, decoding it would be guaranteed to restore it
to the state before encoding.

The idea to 'serialize' a class into a hash without any way of escaping
already serialized input but with guaranteed, silent collisions should
the 'magic key' already appear in the input data, as exemplified by

is really just incredibly silly.

Re: Seeking facts and opinion about "Class::Unbless"

Hi Rainer,

I was mostly looking for prior implementations and opinions on the package  
name. If anybody has opinions about this, let them be heard.

About your reply about the implementation:

On Monday, June 15, 2015 at 2:17:56 PM UTC+2, Rainer Weikusat wrote:
Quoted text here. Click to load it

I can some some of your point. If "unbless" were to convert a blessed refer
ence like:

    bless { key => "value" }, "ModuleA";  


    { __class__ => 'ModuleA', obj => { key => "value" } }

That would mean there is only one implementation for both hashes and arrays
, and it could handle blessed scalars as well. Simpler code. I might consid
er it, but right now it ain't broke, so I'll probably leave it.

But that is where our agreement ends, I think.

There will always be a need to trust that the magic string is indeed magic  
and not found in the input data. If we were to use a somewhat less magic st
ring, say "class", I can design this input that makes the "unbless"/"rebles
s" cycle break:

     # A blessed reference whose conversion is the purpose of this module

     bless({ key => "value" }, "ModuleA"),

     # A non-blessed hash-reference carefully designed to demonstrate the
     # need for a magic string such as "__class__". This is the test case
     # designed to break unbless / rebless

     { class => "SomeUnrelatedClassConcept", obj => [] }

"unbless" would do the expected thing for the first element, and would leav
e the second element unaltered. "rebless" would rebless the first element a
s expected, consider the second element and bless the [] into the "SomeUnre
latedClassConcept" package yielding this output that differs from the input
 given to "unbless":

     bless({ key => "value" }, "ModuleA"),
     bless([], "SomeUnrelatedClassConcept")

Class::unbless fails if an ordinary unblessed perl hash has a magic-string  
key. If there is no assumption that the magic string is not present already
 in the input, I will always be able to create a test case that will break  
the "unbless"/"rebless" cycle. Yes, it is brittle by nature. Don't use it i
f it doesn't suit your needs. It suits mine.

Sure, I guess we could get into further escaping/safeguarding land and expl
icity deal with hashes that happen to have a "class" element in them, but t
hat is not part of my itch. I'll use the __class__ magic key, assume it isn
't in the input, and be done with it. Patches welcome :-)


Re: Seeking facts and opinion about "Class::Unbless"

Quoted text here. Click to load it

As I pointed out in the part of my posting you deleted, this is
absolutely not the case: There has to be a way to detect something which
looks like the encoded representation in the input and a way to escape
that such that it is preserved as is instead of being erroneously
decode. This isn't exactly rocket science and I described a way to
accomplish that.

Re: Seeking facts and opinion about "Class::Unbless"

Quoted text here. Click to load it

Addition: The usual way to accomplish that with "inline mutilation" as
encoding principle would be to prefix the magic string to any occurrence
of itself in the input data, eg, the output of

bless { __class__ => 1968, __class____class__ => 3363 }, 'Topflappen';

would be encoded as

{ __class__ => 'Topflappen',__class____class__ => 1968, __class____class____class__ => 3363 }

That for instance how input lines containing only dots would be handled
in SMTP. But that's more difficult to implement and less easily

Re: Seeking facts and opinion about "Class::Unbless"

Quoted text here. Click to load it

I am not sure the unbless is a smart name for this. In my opinion
unbless should be reserved for an operation doing the opposite of bless,
no more and no less.

There is a recent thread om perl5.porters about that specific

A real implementation would of course not do a copy like Acme::Curse

This is not to say that your proposed functionality is a bad idea. I
have implemented the same functionality again and again.  


Re: Seeking facts and opinion about "Class::Unbless"

Quoted text here. Click to load it

[flattening objects]

Quoted text here. Click to load it

Insofar the idea is to serialize 'Perl classes' into JSON such that
cooperating Perl code can recover them, any serialization module will do
the trick for you as the result can be put into JSON as string data. If
the serialized implementation is binary, the obvious idea would be to
run it through a base64 encoder prior to turning it into a JSON
string. If a more structured format is desired despite this will then
need to be serialized afterwards, it is really easy to accomplish this
such that it will be usable in all conceivable situations. I provided a
complete example of such an 'unclassing' scheme which surely could be
implemented with less than 50 lines of code (I didn't need this myself
so far and would probably prefer just serializing to text or
binary). Creating Perl modules which can be reused is easy, easier than
getting ones face onto the CPAN "our free software runs your company"

So why implement this (badly!) "over and over again"?

unblessing (was: Seeking facts and opinion about "Class::Unbless")

Quoted text here. Click to load it

Acme::Curse does other unpleasant things, namely, it doesn't handle glob
references and 'unblesses' code references by creating anonymous
subroutines doing a tail-call goto to the original routine, IOW, as
opposed to what the documentation says, the result has a top-level link
to the original input.

A sensible implementaion (C/XS-code which does the inverse of bless) is
available here

Re: Seeking facts and opinion about "Class::Unbless"

Hej Peter,

On Tuesday, June 16, 2015 at 9:58:20 AM UTC+2, Peter Makholm wrote:
Quoted text here. Click to load it

Thanks for your excellent point. "unbless" truly does more than just un-"bl
ess" and hence is a bad name.

I'll stay true to the MooseX::Storage inspiration and rename

    use Class::Unbless qw(unbless rebless)


    use Class::Storage qw(packObjects unpackObjects)

Find it at:

Quoted text here. Click to load it

Re: Seeking facts and opinion about "Class::Unbless"

Quoted text here. Click to load it

I figure reporting the possibility of silent data corruption due to lack
of an escape mechanism is probably useless ...

Re: Seeking facts and opinion about "Class::Unbless"

On Wednesday, June 24, 2015 at 12:10:57 AM UTC+2, Rainer Weikusat wrote:
Quoted text here. Click to load it

I've done it for you:

Rainer, as I wrote earlier:
Quoted text here. Click to load it


Re: Seeking facts and opinion about "Class::Unbless"

Quoted text here. Click to load it


Quoted text here. Click to load it

As 'food for thought' suggestion (evil proof-of-concept code, this
destroys the packed input on unpacking by turning the embedded data
structures into objects instead of copying them)

use Devel::Peek;
use Scalar::Util qw(blessed reftype);

use constant MAGIC => 'X19jbGFzc19fCg';

my $o = bless({__class__ => 'It's magic', numbers => bless([MAGIC,1,2], 'Data')}, 'Example');

my %packers = ('' =>    sub { $_[0] },
           HASH => \&pack_hash,
           ARRAY => \&pack_array);

sub packit
    return $packers->($_[0]);

sub pack_hash
    my %h = %;
    $_ = packit($_) for values(%h);
    return wrap(\%h, blessed($_[0]));

sub pack_array
    my @a = @;
    $_ = packit($_) for @a;
    return wrap(\@a, blessed($_[0]));

sub wrap
    my ($d, $c) = @_;
    return $d unless defined($c) || (reftype($d) eq 'ARRAY' && @$d == 3 && $d->[0] eq MAGIC);
    return [MAGIC, $c, $d];

my $p = packit($o);

my %unpackers = (
         HASH => \&unpack_hash,
         ARRAY => \&unpack_array);

sub unpackit
    my $d = $_[0];
    my $c;

    return $d unless reftype($d) eq 'ARRAY' && @$d == 3 && $d->[0] eq MAGIC;

    $c = $d->[1];
    $d = $unpackers->($d->[2]);
    bless($d, $c) if defined($c);

    return $d;

sub unpack_hash
    $_ = unpackit($_) for values(%);
    return $_[0];

sub unpack_array
    $_ = unpackit($_) for @;
    return $_[0];

my $oo = unpackit($p);


Roughlt as I expected, it could be implemented in 'about fifty lines of

Site Timeline