novacik novacik - 10 months ago 51
Perl Question

Unblessing Perl objects and constructing the TO_JSON method for convert_blessed

In this answer I found a recommendation for a simple

method, which is needed for serializing blessed objects to JSON.

sub TO_JSON { return { %{ shift() } }; }

Could anybody please explain in detail how it works?

I changed it to:

sub TO_JSON {
my $self = shift; # the object itself – blessed ref
print STDERR Dumper $self;

my %h = %{ $self }; # Somehow unblesses $self. WHY???
print STDERR Dumper \%h; # same as $self, only unblessed

return { %h }; # Returns a hashref that contains a hash.
#return \%h; # Why not this? Works too…

Many questions… :( Simply, I’m unable to understand 3-liner Perl code. ;(

I need the
but it will filter out:

  • unwanted attributes and

  • unset attributes too (e.g. for those the
    predicate returns false)

This is my code – it works but I really don't understand why the unblessing works…

use 5.010;
use warnings;
use Data::Dumper;

package Some;
use Moo;

has $_ => ( is => 'rw', predicate => 1,) for (qw(a1 a2 nn xx));

sub TO_JSON {
my $self = shift;
my $href;
$href->{$_} = $self->$_ for( grep {!/xx/} keys %$self );
# Same mysterious unblessing. The `keys` automagically filters out
# “unset” attributes without the need of call of the has_${attr}
# predicate… WHY?
return $href;

package main;
use JSON;
use Data::Dumper;

my @objs = map { Some->new(a1 => "a1-$_", a2 => "a2-$_", xx=>"xx-$_") } (1..2);
my $data = {arr => \@objs};
#say Dumper $data;
say JSON->new->allow_blessed->convert_blessed->utf8->pretty->encode($data);

EDIT: To clarify the questions:

  • The
    %{ $hRef }
    derefences the
    (getting the hash pointed to by the reference), but why get a plain hash from a blessed object reference

  • In other words, why the
    is a hashref?

  • I tried to make a hash slice like
    @{$self}{ grep {!/xx/} keys %$self}
    but it didn't work. Therefore I created that horrible

  • If the
    is a hashref, why the
    keys %$self
    returns only attributes having a value, and not all declared attributes (e.g. the
    too – see the

sub TO_JSON { return { %{ shift() } }; }
                     | |  |
                     | |  L_ 1. pull first parameter from `@_`
                     | |        (hashref/blessed or not)
                     | |     
                     | L____ 2. dereference hash (returns key/value list)
                     L______ 3. return hashref assembled out of list

In your TO_JSON() function { %h } returns a shallow hash copy, while \%h returns a reference to %h (no copying).