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

If I try to verify that: $a=$a <operator> $b; is same as $a <operator> = $b; My script using $a=$a <operator> $b produces a warning message. The test script is:
my %baseball = ( mets => "new york", orioles => "baltimore", twins => "minnesota" ); if ( $baseball{yankees}=$baseball{yankees}.$baseball{mets} ) { foreach $_ (keys %baseball) { print "$_ => $baseball{$_}\n"; } }
...attempting to add yankees=>"new york" (not using the ".=" form) produces:
Use of uninitialized value in concatenation(.)or string at /test.pl li +ne 13. orioles => baltimore yankees => new york twins => minnesota mets => new york
Why the warning? ...Thanks

Replies are listed 'Best First'.
Re: problem unless I use ".="
by demerphq (Chancellor) on May 13, 2007 at 17:40 UTC

    FWICT you have ample explanations of why the . operator throws a warning, but it looks like nobody* has given a proper explanation of why .= does not throw a warning. And the reason is simple, it is special cased not to. Most (but not all) of the mutator style operators of the form X= (where X could be any operator symbol) are special cased not to throw warnings when used on undef lvalues. Similar rules apply to ++ and --. This is because its generally agreed that its "ok" to do stuff like $hash{somekey}++ or $hash{somekey}.=$str when $hash{somekey} doesn't have a defined value.

    * well, liverpole gives an explanation but its not clear to me if the documentation he is referencing explains what he thinks it does. (UPDATE, actually im pretty sure it doesnt. :-)

    ---
    $world=~s/war/peace/g

      demerphq & liverpole... Thank you for clearing that up. I was unaware of such "special cased" scenarios.I appreciate your help! Also, I didn't know about the existence of the "perlop (under Assignment Operators)" reference. Again... Thanks!
Re: problem unless I use ".="
by liverpole (Monsignor) on May 13, 2007 at 14:29 UTC
    Hi cgmd,

    It's because the value of $baseball{mets} is not defined at the point you're trying to use it.

    Note how the warning goes away with something like:

    my $yanks = $baseball{yankees} || ""; my $mets = $baseball{mets} || ""; if ( $baseball{yankees} = $yanks.$mets ) { foreach $_ (keys %baseball) { print "$_ => $baseball{$_}\n"; } }

    You could also do it this way:

    if ( $baseball{yankees}=($baseball{yankees} || ""). ($baseball{mets} | +| "") ) { foreach $_ (keys %baseball) { print "$_ => $baseball{$_}\n"; } }

    This is all assuming, of course, that you really mean to do the assignment $baseball{yankees}=$baseball{yankees}.$mets.

    If instead you are doing a comparison, you'd probably want to use eq (for string comparisons) rather than == (for numerical comparisons).


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: problem unless I use ".="
by derby (Abbot) on May 13, 2007 at 14:58 UTC

    Others have given you the reason for the warning but this snippet causes some concern:

    if ( $baseball{yankees}=$baseball{yankees}.$baseball{mets} )
    Assignment inside an if is unusual .. do you mean to use assignment (=) here or do you want to compare strings? If compare, you want the string eq operator not the assignment operator (=) nor the numerical == operator.
    if ( $baseball{yankees} eq $baseball{yankees}.$baseball{mets} ) {
    (but that doesn't make much sense with your examples so ... )

    -derby
Re: problem unless I use ".="
by chargrill (Parson) on May 13, 2007 at 14:30 UTC

    Pretty sure you'll get the warning regardless if you use $a = $a . $b vs. $a .= $b, especially given the above code.*

    In your above code, $baseball{yankees} hasn't been initialized, hence the warning that you're trying to use an uninitialized value in a concatenation.

    You can get more detail if you use diagnostics; at the top of your program, which yeilds:

    Use of uninitialized value in concatenation (.) or string at -e line 1 (#2) (W uninitialized) An undefined value was used as if it were already defined. It was interpreted as a "" or a 0, but maybe it was a mistake. To suppress this warning assign a defined value to your variables.

    To help you figure out what was undefined, perl tells you what operation you used the undefined value in. Note, however, that perl optimizes your program and the operation displayed in the warning may not necessarily appear literally in your program. For example, "that $foo" is usually optimized into "that " . $foo, and the warning will refer to the concatenation (.) operator, even though there is no . in your program.

    What are you trying to do, exactly?

    If you just want to add a new key/value pair to your hash,

    $baseball{yankees} = 'new york'; # OR $baseball{yankees} = $baseball{mets};

    ... will suffice.

    * Update: Incorrect



    --chargrill
    s**lil*; $*=join'',sort split q**; s;.*;grr; &&s+(.(.)).+$2$1+; $; = qq-$_-;s,.*,ahc,;$,.=chop for split q,,,reverse;print for($,,$;,$*,$/)
Re: problem unless I use ".="
by cgmd (Beadle) on May 13, 2007 at 14:48 UTC
    I don't get the warning with:
    my %baseball = ( mets => "new york", orioles => "baltimore", twins => "minnesota" ); if ($baseball{yankees} .= $baseball{mets}) { # edited foreach $_ (keys %baseball) { print "$_ => $baseball{$_}\n"; } }
      Actually, you get a syntax error there, but only because you're missing the if keyword :-)

      But you're correct; you don't get a warning.  And that's because you're not trying to use the value of $baseball{yankees}, you're only modifying it (ie. appending to it).

      Note that you do get a warning if $baseball{mets} is undefined, as in:

      use strict; use warnings; my %baseball = ( orioles => "baltimore", twins => "minnesota" ); if ($baseball{yankees} .= $baseball{mets}) { foreach $_ (keys %baseball) { print "$_ => $baseball{$_}\n"; } } __END__ Use of uninitialized value in concatenation (.) or string at test.pl l +ine 10.

      s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
        Then what is being stated is that the line of code:
        if ( $baseball{yankees} = $baseball{yankees} . $baseball{mets}
        is not identical to:
        if ($baseball{yankees} .= $baseball{mets})
        Does this refute the original premise that: $a=$a <operator> $b; is same as $a <operator> = $b; (Taken from "Beginning Perl" by Lee & Cozens)?