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

print "print "$n1 plus $n2 is ", $n1 + $n2, "\n";

where $n1 and $n2 are integers pulled from STDIN and chomped, outputs "4 plus 2 is 6" like it's supposed to.

However, what I tried to use before:

print "$n1 plus $n2 is " . $n1 + $n2 . "\n";

returns

Argument "4 plus 2 is 4" isn't numeric in addition (+) at operators.pl line 10, <STDIN> line 2.

but then goes on running the script. This is a warning, I assume, as it doesn't appear when I remove the warning flag from my hashbang line.

Also, this only outputs 6 as opposed to 4 plus 2 is 6.

Why does it behave this way?
It's not a huge deal as I've got it doing what I want now, but I'm curious.

Replies are listed 'Best First'.
Re: This is odd.
by almut (Canon) on May 22, 2008 at 23:47 UTC

    This is a precedence problem. You need to put parentheses around the ($n1 + $n2).

    Otherwise, Perl adds the result of concatenating the string "$n1 plus $n2 is " with $n1 — i.e.the string "4 plus 2 is 4" — with $n2. This string numerically evaluates to the initial 4, so you do get the result 6.

Re: This is odd.
by dragonchild (Archbishop) on May 23, 2008 at 00:12 UTC
    +, -, and . are operators with the same precedence and they have left-associativity. Thus, your line is parsed:
    print( ((("$n1 plus $n2 is " . $n1) + $n2) . "\n") );
    Read perlop for more info.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: This is odd.
by hesco (Deacon) on May 23, 2008 at 05:10 UTC
    And put one more way, if I may . . .

    The dot operator is used to concatenate string data into a single scalar. Once you've done that, you're trying to use a (+) operator to do arithmetic between a string scalar and an integer, which is not defined. You confuse the poor compiler this way.

    -- Hugh

    if( $lal && $lol ) { $life++; }
      Oh, my. Poor compiler. What do the commas do, then? I don't know why I used them, probably picked them up at some point dabbling around in Perl earlier.
        They make print aware that it's dealing with a list of different items, due to list operator precedence rules.

        According to perlop:

        In the absence of parentheses, the precedence of list operators such as print, sort, or chmod is either very high or very low depending on whether you are looking at the left side or the right side of the operator. For example, in
        @ary = (1, 3, sort 4, 2); print @ary; # prints 1324
        the commas on the right of the sort are evaluated before the sort, but the commas on the left are evaluated after. In other words, list operators tend to gobble up all the arguments that follow them, and then act like a simple TERM with regard to the preceding expression. Note that you have to be careful with parentheses:
        # These evaluate exit before doing the print: print($foo, exit); # Obviously not what you want. print $foo, exit; # Nor is this. # These do the print before evaluating exit: (print $foo), exit; # This is what you want. print($foo), exit; # Or this. print ($foo), exit; # Or even this.
Re: This is odd.
by casiano (Pilgrim) on May 23, 2008 at 06:51 UTC
    The behavior is the correct one if you supress the warnings flag:
    p2@nereida:~/src/perl/testing$ cat precedence1.pl my $n1 = 2; my $n2 = 4; print "$n1 plus $n2 is " . $n1 + $n2 . "\n";
    When you run this program there are no warnings:
    pp2@nereida:~/src/perl/testing$ perl precedence1.pl 6
    However:
    pp2@nereida:~/src/perl/testing$ cat precedence2.pl use warnings; my $n1 =2; my $n2 = 4; print "$n1 plus $n2 is " . $n1 + $n2 . "\n";
    Issues the warning:
    pp2@nereida:~/src/perl/testing$ perl precedence2.pl Argument "2 plus 4 is 2" isn't numeric in addition (+) at precedence2. +pl line 6. 6
    The warning flag and the Warnings module are full of heuristics that helps you most of the time.

    Whenever you have problems with operator priorities use the p option of Deparse like this:

    pp2@nereida:~/src/perl/testing$ perl -MO=Deparse,-p precedence2.pl use warnings; use strict 'refs'; (my $n1 = 2); (my $n2 = 4); print(((("$n1 plus $n2 is " . $n1) + $n2) . "\n")); precedence2.pl syntax OK
    It will tell you the execution order of the involved operations.

    Observe that the extraordinary thing is that the operation

    (((("$n1 plus $n2 is " . $n1) + $n2) . "\n"))
    still gives 6!. This is because the phrase starts with 4 plus .... There is some irony here.

    The first time I stomped in this sort of "Perl priority problems" I was puzzled. But if you live with it time enough you start to appreciate the fun of it

    Hope it helps

    Casiano

Re: This is odd.
by hesco (Deacon) on May 23, 2008 at 06:05 UTC
    Your commas delimit the elements of a list, which are printed, one after another. In your use of the commas, the precendence is respected in a way that it does what you mean here. everything between the commas is a single element of the list or array, and must be evaluated itself, before the list is put together. That is different that the dot concatenation string operator.

    -- Hugh

    if( $lal && $lol ) { $life++; }
      Ooh, excellent. Thanks so much.
Re: This is odd.
by roboticus (Chancellor) on May 23, 2008 at 11:26 UTC
    JDelmoso:

    Not quite ... an odd number is one having a nonzero remainder after dividing by two. Two, four and six are all even!

    </tongue_in_cheek>

    ...roboticus

Re: This is odd.
by JDelmoso (Novice) on May 23, 2008 at 00:19 UTC
    Oh, I see. Thanks.