http://qs321.pair.com?node_id=1068397

ccn has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks,

there are two subroutine calls in the script below.

use warnings; sub foo { my $val = $_[0]; } my %bar; my $baz; # this line does not generate warnings foo( $bar{not_existing} ); # this line generates two warnings foo( $bar{$baz} );

Output I have is the following:

Use of uninitialized value $baz in hash element at t.pl line 10.
Use of uninitialized value in scalar assignment at t.pl line 2.

The question is: Why perl generates 'Use of uninitialized value in scalar assignment' only for the second call of foo and not for the both calls? What's the difference?

In both cases @_ in foo contains an alias of not existing value of not existing key of %bar, you know.

Replies are listed 'Best First'.
Re: Inconsistency of 'Use of uninitialized value in scalar assignment' warning
by Athanasius (Archbishop) on Dec 26, 2013 at 08:43 UTC

    As LanX observes, there are really two separate issues here:

    (1) $bar{not_existing} vs. $bar($baz}

    $bar{undef()} generates the same Use of uninitialized value in hash element error. The difference is that $bar{not_existing} only happens (in this case) to access a non-existent element, but $bar($baz} (with $baz undefined) necessarily does so. So the latter case is guaranteed to fail, making it safe to issue a warning; but the former case might arise within otherwise-valid programming logic, so a warning is not issued. Well, that’s my guess, anyway.

    (2) use of uninitialized value in scalar assignment within sub foo

    I don’t know what makes the difference here, but I note that under some circumstances the warning goes away:

    #! perl use strict; use warnings; use Data::Dump; sub foo { dd \@_; my $val = $_[0]; } my %bar; my $baz; foo( $bar{$baz} );

    Output:

    18:39 >perl 814_SoPW.pl Use of uninitialized value $baz in hash element at 814_SoPW.pl line 28 +. [undef] 18:39 >

    Maybe a product of the way aliasing works?

    Hope that helps (a little),

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Inconsistency of 'Use of uninitialized value in scalar assignment' warning
by dave_the_m (Monsignor) on Dec 26, 2013 at 12:27 UTC
    To avoid autovivification of hash elements that might only end up getting used in rvalue context, when you call a function with a hash element as an arg, e.g. foo($hash{$key}), perl invokes a special mechanism.

    When perl initially tries to retrieve the hash element before calling the function, if the element doesnt exist, then rather than autovivifying and creating a new null element, it creates a temporary proxy object which has the hash and the key attached to it. When at this point the key is being evaluated, this triggers the first uninit warning. Later inside the function, the value of the proxy object is evaluated during the assignment, which triggers a second (redundant) uninit warning as the undef key is used to retrieve the hash element.

    Dave.

      The difference between two foo call cases is evaluation of undefined $baz variable. Isn't it? So we got first warning.

      But why we got the second warning? In both cases proxy object must be created and be evaluated during the assignment the same way, and must produce the same warnings.

        I think people are still thinking that the second undef warning is due the hash *value* not existing; its not. Both warnings are being generated by trying to evaluate the *key*. In the first foo() call in the OP, the key isn't undef, so it doesn't generate any warnings.

        Dave.

Re: Inconsistency of 'Use of uninitialized value in scalar assignment' warning
by LanX (Saint) on Dec 26, 2013 at 08:26 UTC
    What rather surprises me is the order of errors.¹

    In the first call Perl accepts passing an yet undefined hash value for the key "not_existing". E.g. you may want to populate it in foo!²

    In the second call it warns about an undefined key. Keys are strings not undef which must be mapped to "".

    Different things.

    Cheers Rolf

    ( addicted to the Perl Programming Language)

    update

    ¹) ah ok, now that I can test it's obvious why! Both warnings are for the second call. The first doesn't cause warnings.

    ²) demonstration of a legal use case

    DB<102> sub populate { $_[0]="xxx" } DB<103> populate $hash{not_existent} => "xxx" DB<104> \%hash => { not_existent => "xxx" } DB<105> use warnings; populate $hash{+ undef} Use of uninitialized value in hash element at ...
      Yes. You can experiment with simpler
      foo($hash{ undef() });
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Inconsistency of 'Use of uninitialized value in scalar assignment' warning (old discussion)
by LanX (Saint) on Dec 27, 2013 at 01:17 UTC
    Now that I understand your concern, I remembered that we discussed it before...

    see Unexpected warning

    Actually I don't see the practical problem to get two instead of just one warning.

    And if you planed to switch off the first warning, I can't find a way the second wouldn't be automatically suppressed too.

    DB<143> use warnings; no warnings 'uninitialized'; $h{+undef} => undef DB<144> sub tst { my $x=$_[0] } DB<145> use warnings; no warnings 'uninitialized'; tst $h{+undef} => undef DB<146> use warnings; tst $h{+undef} Use of uninitialized value in hash element at (eval 108)[multi_perl5db +.pl:644] line 2.

    So what's the problem?

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: Inconsistency of 'Use of uninitialized value in scalar assignment' warning
by marinersk (Priest) on Dec 26, 2013 at 22:54 UTC

    I will attempt to clarify my previous answer, given questions sent to me offline.

    The question is: Why perl generates 'Use of uninitialized value in scalar assignment' only for the second call of foo and not for the both calls? What's the difference?

    The first call specifies a key. The value is undefined, but the key is not.
    The second one has an undefined key.

    Hopefully this code will demonstrate the difference -- the only error generated is when the key is undefined. The value has nothing to do with the problem.

    #!/usr/bin/perl use strict; use warnings; my %bar = (); $bar{not_existing} = 1; $bar{"is_existing"} = 1; my $bar1 = $bar{not_existing}; my $bar2 = $bar{"is_existing"}; my $bar3 = $bar{really_not_existing}; my $key4 = "value_not_existing"; my $bar4 = $bar{$key4}; my $key5; my $bar5 = $bar{$key5}; exit; __END__ C:\Steve\devcvs\mapgen>\steve\t\t2.pl Use of uninitialized value $key5 in hash element at C:\steve\t\t2.pl l +ine 19.