I'm trying to untangle some legacy code where an operation is done on $value iff its size is more than x (where x is a hard coded int). This is what it currently looks like:
if (scalar(@{$value}) > x) {
...
}
As with all legacy code, this $value can be almost anything (hash, scalar, array) although it's expected to be an array of different objects. This code currently fails with a "Not an ARRAY reference" around 5% of the time and I'm trying to figure out what's the possible $value that can break it.
I assumed it might fail if the $value is undefined so I even gave it a || [] but to no avail (same error):
if (scalar(@{$value || []}) > x) {
...
}
I'm also trying to figure out why I need the @{}? My understanding is that that evaluates $value in a list context so that scalar can later ensure I get the size. Does that make the code more robust or can I just directly use scalar $value? Does @{} even do what I think it does?
I'm using perl 5.8.
You have two questions there. I'll answer them separately:
@{}
doing?When you write @{$thing}
, you are dereferencing $thing
into an array. As you have noticed, this only works when $thing
is an array reference. (Other dereferencing operators are %{$thing}
for hash references and ${$thing}
for scalar references.)
You do need a dereferencing operator there. Consider this:
my $arrayref = [ 'Alice', 'Bob', 'Charlie' ];
my $hashref = { x => 4, y => 5 };
my $string = "Hello, world";
for my $thing ($arrayref, $hashref, $string) {
print "thing --> ", $thing, "\n";
print "scalar(thing) --> ", scalar($thing), "\n";
}
Output:
thing --> ARRAY(0x7f3b8054e468)
scalar(thing) --> ARRAY(0x7f3b8054e468)
thing --> HASH(0x7f3b80560678)
scalar(thing) --> HASH(0x7f3b80560678)
thing --> Hello, world
scalar(thing) --> Hello, world
There's no point in forcing $thing
to a scalar context. It's already a scalar!
If you don't know what kind of reference is contained in $thing
, you can use Ref::Util
to inspect it:
use Ref::Util qw( is_arrayref is_hashref );
for my $thing ($arrayref, $hashref, $string) {
if (is_arrayref($thing)) {
print "array: thing --> ", @{$thing}, "\n";
print "array: scalar(thing) --> ", scalar(@{$thing}), "\n";
}
elsif (is_hashref($thing)) {
print "hash: thing --> ", %{$thing}, "\n";
print "hash: scalar(thing) --> ", scalar(%{$thing}), "\n";
}
else
{
print "else: thing --> ", $thing, "\n";
}
}
Output:
array: thing --> AliceBobCharlie
array: scalar(thing) --> 3
hash: thing --> y5x4
hash: scalar(thing) --> 2/8
else: thing --> Hello, world
Observations:
print
outputs every element with no separators: AliceBobCharlie
3
print
outputs every pair with no separators: y5x4
2/8