6
votes

I have these two snippets of code which seemingly should produce the same result, but the latter results in an error.

1:

my $href = undef;
my @values = values %{ $href };
# OK - @values is empty

2:

my $href = undef;
my %hash = %{ $href }; # <-- Error here
my @values = values %hash;
# ERROR: Can't use an undefined value as a HASH reference

Why does having values in the same line allow it to work? I'd rather them both throw an error, since using an undefined value as a hash reference is clearly a mistake. I don't have any more recent versions of perl to test on, but this was reproducible in 5.8.8 and 5.10.1.

2
I think this similar SO question about array references also applies here. ikegami says "Dereferences autovivify in lvalue context (meaning when a modifiable value is expected)." perldoc -f values says "Note that the values are not copied, which means modifying them will modify the contents of the hash." - ThisSuitIsBlackNot
If this were autovivification-related, I would expect no autovivification to cause an error in the first snippet. It does not. - AKHolland
@AKHolland That's because autovivification simply leaves it as undef. Use the warn or strict option, e.g. no autovivification qw(fetch delete exists strict); $h = undef; values %$h; gives Reference vivification forbidden. See brian d foy's article Turn off autovivification when you don’t want it - ThisSuitIsBlackNot

2 Answers

0
votes

Auto-vivification is the automatic creation of a variable when deferencing undef

my $ref;
say $ref // "[undef]";   # /  # Outputs: [undef]
$ref->{abc} = 123;            # This autovivifies a hash and a reference to it.
say $ref // "[undef]";        # Outputs: HASH(0x...)
say for keys %$ref;           # Outputs: abc

Autovivification only happens when the dereferencing is in lvalue context.

my $ref;
%$ref = ( abc => 123 );   # Autovivifies
my $ref;
my %h = %$ref;            # Error

Arguments to subs are evaluated in lvalue context. I don't know if there's any consistency as to whether the operands of named operators (like values) are evaluated in lvalue context or not, but it apparently is the case for values's operand.

my $ref;
say $ref // "[undef]";   # /  # Outputs: [undef]
values %$ref;
say $ref // "[undef]";        # Outputs: HASH(0x...)

When autovification doesn't occur, you're left with an attempt to deference undef, which makes no sense, and thus causes an error.

-1
votes

Values is a function and it accepts a hash, an array or a generic expression as an argument (as stated here) . If you pass undef as an argument to "values", it simply detects it as empty and returns no value. On the other hand, if you try to explicitly convert undef to an hash, it will fail, because it's missing key-value pair.

EDIT: Just to be precise. This error happens with the "strict" directive (which you should always use, anyway).