8

Why does this not work?

my $myHashEncoded = encode_json \%myHash;
my %myHashDecoded = decode_json($myHashEncoded);

I get the error:

Reference found where even-sized list expected at ...

So I changed it to:

my $myHashEncoded = encode_json \%myHash;
my $myHashDecoded = decode_json($enableInputEncoded);

But then obviously %myHash is not the same as $myHashDecoded.

How do I restore a proper hash from the JSON string?

3
  • 1
    Which module are you getting encode_json and decode_json from? Commented Jun 10, 2015 at 14:23
  • I included use JSON; Commented Jun 10, 2015 at 14:40
  • 1
    You can dereference hash, my %myHashDecoded = %{ decode_json($enableInputEncoded) }; Commented Jun 10, 2015 at 14:40

4 Answers 4

13

Assuming you are using JSON.pm, the documentation says:

The opposite of encode_json: expects an UTF-8 (binary) string and tries to parse that as an UTF-8 encoded JSON text, returning the resulting reference.

So you are getting back what you put in. You're putting in a hashref and you're getting a hashref back.

If you want a regular hash, then you just dereference it as you would any other hashref:

my $myHashRefDecoded = decode_json($myHashEncoded);
my %myHashDecoded = %$myHashRefDecoded;
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the quick relpy. And sorry for my ignorance regarding the documentation.
This really helped me grok some aspects of Perl that (as a newcomer) didn't make a lot of sense to me. Thanks!
4

You are encoding a reference to a hash (encode_json \%myHash), which is correct. So when you decode your JSON string you are receiving a reference to a hash. Prepend a % sigil to a hash reference to dereference it.

$myHashReferenceDecoded = decode_json($myHashReferenceEncoded);
%myHashDecoded = %$myHashReferenceDecoded;

Comments

2

On the following line, you do two things: you create a reference to the hash (\), and you encode the result (encode_json):

my $myHashEncoded = encode_json(\%myHash);

One the following line, you decode the JSON (decode_json), but you don't "undo" the reference.

my %myHashDecoded = decode_json($myHashEncoded);

The real inverse operation would involve a hash derereference.

my %myHashDecoded = %{ decode_json($myHashEncoded) };

But that needlessly makes a (shallow) copy of the hash. Maybe you should just work with the reference instead.

my $myHashDecoded = decode_json($myHashEncoded);

By the way, the reason a reference is used is that it's impossible to pass a hash to a sub or to return a hash from a sub. Only list of scalar can be passed and returned.

Comments

1

The JSON API is consistent. If you use a reference to a hash when encoding, you also get a hash reference when decoding. So if you want to store the result in a pure hash variable, you have to dereference the result of decode_json with %{ ... }.

Solution:

my $myHashEncoded = encode_json \%myHash;
my %myHashDecoded = %{ decode_json($myHashEncoded) };

Note that dereferencing a hash is a costly operation. You should really consider if using directly the reference is not enough in your code.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.