I was trying to tie an hash (or hashref) in order of tracking variable usages.
Everything is working for simple cases, but when I tried to use my module on some real code I had this error:
hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)
I've replicated the error using the following code:
use Tie::Hash::Usages;
use JSON;
my @arr = (
{
key1 => "ac",
key2 => 12,
key3 => 12
},
);
my %tied_hash;
tie %tied_hash, 'Tie::Hash::Usages';
$tied_hash{key1} = \@arr;
my @val = $tied_hash{key1};
print encode_json(\@val)."\n\n"; #this works
print encode_json($tied_hash{key1}); #this doesn't
The same code works with a plain hash.
I'd need this to work also in the second case, the code base is huge and I don't want to change it or live with the doubt that something somewhere will not work in some particular case.
package Tie::Hash::Usages;
use strict;
use warnings;
use Tie::Hash;
use vars qw(@ISA);
@ISA = qw(Tie::StdHash);
sub TIEHASH {
my ($class, $tracker, $filename) = @_;
my %hash;
bless \%hash, $class;
}
sub STORE {
my ($self, $key, $val) = @_;
$self->{$key} = $val;
}
sub DELETE {
my ($self, $key) = @_;
delete $self->{$key};
}
sub FETCH {
my ($self, $key) = @_;
return $self->{$key};
}
sub DESTROY {
my $self = shift;
}
1;
perl version: v5.18.2
Minimal demonstration:
use JSON::XS qw( encode_json );
use Tie::Hash qw( );
our @ISA = 'Tie::StdHash';
{
tie my %tied, __PACKAGE__;
$tied{data} = { a => 1 };
encode_json($tied{data}); # Exception: hash- or arrayref expected ...
}
JSON is a front-end for JSON::PP (default) or JSON::XS (if found). This is a problem with JSON::XS.
A lot of XS code doesn't handle magical variables (which is what $tied{EXPR}
returns), and while JSON::XS has handled magical values since version 1.2, it doesn't for the value directly passed to encode_json
.
This is an existing bug in JSON::XS that can be worked around as follows:
encode_json(my $non_magical = $tied{data})
Bug reported.