3

I have the following code:

$headers;
some_sub( %$headers );

When I call some_sub I get an error:

Can't use an undefined value as a HASH reference at ...

But similar code does not produce an error:

$headers->{ x };

Why doesn't autovivification work the same way in the first example as it does in the second?

UPD

I noted by @ThisSuitIsBlackNot. I really ask:

why my $h; $h->{foo} works and my $h; %$h doesn't

UPD
The real code:

my $email =  Email::Simple->create(
    header =>  [
        To             =>  $address,
        From           =>  $cnf->{ from },
        Subject        =>  $subject,
        'Content-Type' =>  'text/html; charset="utf8"',
        %$headers,
    ],
    body => $body
);
Eugen Konkov
  • 22,193
  • 17
  • 108
  • 158
  • Well, what is the error message saying? `Can't use an undefined value as a HASH reference...` What does that mean? What does that tell you about `$headers`? –  Dec 30 '16 at 18:29
  • 1
    Is that code complete? If so, `$headers` has `undef` as its value and you can't dereference the 'hash' that it doesn't reference. You should be using `use strict; use warnings;` and `my $headers;` at minimum. You could consider `my $headers = { };` too. What did your searching with a term such as 'perl autovivification' return? I used Google and got a number of useful looking articles to follow — Wikipedia, Perl Maven, Perl Monks. Of those, [Explaining Autovivification](http://www.perlmonks.org/?node_id=691557) seems most apposite. – Jonathan Leffler Dec 30 '16 at 18:39
  • 3
    That doesn't produce that error. Could you provide a complete example? – Schwern Dec 30 '16 at 18:40
  • 1
    The `%$headers` has nothing to do with autovivification. It merely attempts to _dereference_ the scalar variable `$headers`, into a hash. With `use strict` in effect it prints that message, but without it it only complains about _uninitialized value_. – zdim Dec 30 '16 at 18:42
  • 1
    I *think* you're really asking why `my $h; $h->{foo}` works and `my $h; %$h` doesn't. I like [ysth's explanation](http://stackoverflow.com/questions/1643717/why-does-an-undef-value-become-a-valid-array-reference-in-perl#comment1514904_1643894): "in general, things that are only reading from a dereference won't autovivify, while things that may modify what's dereferenced do. The for loop is an example of something that may modify (since $el is aliased into the array and the array may be changed through it). This is only a loose rule, though; there are some rough edges." – ThisSuitIsBlackNot Dec 30 '16 at 20:15
  • @ThisSuitIsBlackNot your commets are very usefull. I will award you on some your answers on last day of hats celebration! I can not award on comments ( – Eugen Konkov Dec 30 '16 at 22:02
  • Thanks for the update, this explains it (see my answer). – zdim Dec 30 '16 at 22:44
  • @EugenKonkov Please don't do that, I'd rather earn my imaginary internet points on merit alone :) This was a really interesting question, thanks for posting it! – ThisSuitIsBlackNot Dec 31 '16 at 16:39
  • @ThisSuitIsBlackNot: In any case I am planning to earn my points too: the `Philantropist` hat. So you will be my victim :D – Eugen Konkov Dec 31 '16 at 19:49

2 Answers2

5

%$hash absolutely does autovivify when passed to a sub.

$ perl -Mstrict -wE'my $foo; say $foo // "undef"'
undef

$ perl -Mstrict -wE'sub f { } my $bar; f(%$bar); say $bar // "undef"'
HASH(0x10b50e0)

The error message comes from something else going on in some_sub, perhaps an improper assignment from @_.

ikegami
  • 367,544
  • 15
  • 269
  • 518
mob
  • 117,087
  • 18
  • 149
  • 283
  • 2
    "`%$hash` absolutely does autovivify when passed to a function (user or builtin)" True for some operators (e.g. `keys`), but not others (e.g. `length`). – ThisSuitIsBlackNot Dec 30 '16 at 20:37
5

Note   Code added to the question demostrates why autovivification doesn't happen.

Short   Your sub takes a list (hash) which has an anonymous array as an element – and %$headers is buried in that array. It is the anon array that is the scalar aliased to, thus there is no requirement for %$headers to be modifiable. Thus no autovivification happens, and you get the fatal runtime error described below, as dereferencing is attempted on an undefined reference.


A %$ref autovivifies when used in lvalue context. This may happen in a sub call, see below.

The error you show is due to the use of an undefined reference. For example, the statement

my %hash = %{ $ref };

attempts to copy a hash from the memory location stored in $ref and assign it to %hash. The symbol %hash is created at compile time, but if no hash is found at $ref or if there is nothing in $ref, we get an error. No autovivification happens here. With use strict in effect

perl -wE'use strict; my $h; my %h = %$h; say $h'

this throws the fatal runtime error

Can't use an undefined value as a HASH reference at -e line 1.

When eval-ed to survive that

perl -wE'use strict; my $h; my %h = eval { %$h }; say $h; say "hi"'

it prints a warning about "uninitialized value", an empty line, and then hi. No hash.

However, when used as an argument in a subroutine call it autovivifies

perl -wE'use strict; sub tt { 1 }; my $h; tt( %$h ); say $h'

as this prints the line HASH(0x257cd48), without warnings or errors.

The autovivification happens when a dereferenced object is used in lvalue context, which means that it needs to be modifiable. In a subroutine call the reason for this is that arguments to a function are aliased in @_ so it must be possible to modify them. The same aliasing need makes it happen in a foreach loop, while keys resets the hash iterator. See this post and this post and this post.

Thanks to ThisSuitIsBlackNot for explanation and links.

In your case the %$ref is passed as an element of an anonymous array, and is thus not aliased (the arrayref itself is). So autovivication does not kick in and you get that error.


On autovivification from perlglossary

In Perl, storage locations (lvalues) spontaneously generate themselves as needed, including the creation of any hard reference values to point to the next level of storage. The assignment $a[5][5][5][5][5] = "quintet" potentially creates five scalar storage locations, plus four references (in the first four scalar locations) pointing to four new anonymous arrays (to hold the last four scalar locations). But the point of autovivification is that you don’t have to worry about it.

Also see, for example, an article from Effective Perler

zdim
  • 64,580
  • 5
  • 52
  • 81
  • 2
    Actually, `%$foo` *does* trigger autovivification, *if* used in an l-value context: `perl -Mstrict -MDevel::Peek -wE'my $h; 1 for %$h; Dump $h'` (the `SV = PVHV` indicates that it's a hashref) – ThisSuitIsBlackNot Dec 30 '16 at 19:03
  • @ThisSuitIsBlackNot At the risk of bothering you -- your _if_ above is critical. Of course it comes up when assigned to, and it does when queried for keys as in mob's answer (even without a debugger). But I don't see that it actually gets to that when it is only dereferenced into a hash. Updated. – zdim Dec 30 '16 at 20:36
  • The autovivification rules aren't really consistent (e.g. it doesn't make sense that `exists` would autovivify, but it does), but the best explanation I've seen is that in general, autovivification kicks in when the dereferenced thing could be modified (e.g. in an assignment, a `foreach` loop, arguments to a sub, etc). See the answers to [this question](http://stackoverflow.com/q/6419618), and [this answer](http://stackoverflow.com/a/35031218) to a related question. – ThisSuitIsBlackNot Dec 30 '16 at 20:44
  • @ThisSuitIsBlackNot Thank you, added this. – zdim Dec 30 '16 at 21:42
  • @zdim `>So autovivication does not kick in and you get that error.` :in %$h case it seems if it behaves as `noop` it will be more handy – Eugen Konkov Dec 31 '16 at 13:56