Why does Autovivification occur with keys() and no

2019-04-24 10:36发布

This is a subtlety I found with keys().

$ perl -e 'use warnings; use strict; my $d = { "ab" => 1 }; my @e = keys(%{$d->{cd}});'

$ perl -e 'use warnings; use strict; my $d = { "ab" => 1 }; my %e = %{$d->{cd}};'
Can't use an undefined value as a HASH reference at -e line 1.

I am most puzzled as to why the first snippet would not give an dereferencing error. When I use Data::Dumper, it becomes clear that in the first snippet, $d->{cd}, is autovivified to be {}.

Why does keys need to autovivify? I tried reading the perldoc for it, could not find a satisfying answer. keys does not set an alias ($_, etc) so there is no need for perl to think $d->{cd} needs to be in lvalue context, is there? (I understand if the expression needs to be in lvalue context autovivification happens as explained here.

A relevant post.

2条回答
乱世女痞
2楼-- · 2019-04-24 11:23

Note that keys can indeed be an lvalue (setting the hash's expected number of elements).

But even if keys itself isn't used in an lvalue context, it has a side effect of resetting a hash's iterator.

So it does modify the hash and so gives the dereference an lvalue context, which makes it autovivify.

查看更多
戒情不戒烟
3楼-- · 2019-04-24 11:36

After some research and asking around, I found that this has to do with the fact that $d->{cd} was passed to a subroutine, not the fact that it was keys. For instance,

% perl -e 'use warnings; use strict; my $d = { "ab" => 1 }; sub foo {}; my @e = foo(%{$d->{cd}});'

This will also autovivify; this is because internally perl needs to be able to set an alias to function arguments.

Inside foo(), we have an alias set $_[0] = $d->{cd} But that means $d->{cd} needs to be lvalue-able, since subroutines in perl assume you can do something like $_[0] = "123"; so the autovivification needs to happen.

查看更多
登录 后发表回答