6

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.

AKHolland
  • 4,435
  • 23
  • 35
  • 1
    I think [this similar SO question](http://stackoverflow.com/q/6419618) 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 Nov 11 '14 at 21:15
  • http://www.perlarchive.com/___TLC/7026.shtml http://stackoverflow.com/questions/1643717/why-does-an-undef-value-become-a-valid-array-reference-in-perl – hmatt1 Nov 11 '14 at 21:26
  • If this were autovivification-related, I would expect `no autovivification` to cause an error in the first snippet. It does not. – AKHolland Nov 11 '14 at 21:33
  • 3
    @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](http://www.effectiveperlprogramming.com/2011/07/turn-off-auto-vivification-when-you-dont-want-it/) – ThisSuitIsBlackNot Nov 11 '14 at 21:49

2 Answers2

0

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.

ikegami
  • 367,544
  • 15
  • 269
  • 518
-1

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).

ChatterOne
  • 3,381
  • 1
  • 18
  • 24
  • Please, read carefully before downvoting. As I said, "values" is a function. You're NOT converting when calling it, because values ALSO accepts an expression. – ChatterOne Nov 14 '14 at 15:24
  • That was a poor example, but your explanation is wrong. `values` is not somehow magically detecting that the hashref is `undef` and ignoring it; the hash is autovivified to an empty hash and `values` acts on that. You can see this with the following: `perl -Mstrict -MData::Dump -e 'sub print_args { dd \@_ } my $href; print_args undef; print_args %{ $href }'` which prints `[undef]` followed by `[]` – ThisSuitIsBlackNot Nov 14 '14 at 15:51
  • Furthermore, turning off autovivification causes an exception: `perl -e 'no autovivification qw(fetch strict); my $foo; values %{ $foo }'` gives `Reference vivification forbidden at -e line 1.` – ThisSuitIsBlackNot Nov 14 '14 at 15:54
  • Ok, I see. But I still can't understand what the reason for the error is then, nor why a simple "if defined" check on a function parameter should be magical? I mean, ok, my explanation may be wrong, but what is the correct one? – ChatterOne Nov 14 '14 at 16:12
  • See my comments on the question. This is the same concept as in [this question](http://stackoverflow.com/q/6419618), except with hash references instead of array references. `values` creates an lvalue context, since modifying the results modifies the hash. Dereferences autovivify in lvalue context, so you get an empty hash: `perl -Mstrict=refs -E 'values %$x; say $x'` prints `HASH(0x1c3bd48)` – ThisSuitIsBlackNot Nov 14 '14 at 16:30