http://www.perlmonks.org?node_id=851101

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

Why should I not be surprised that the code below prints 2 and not 4?
File two.pl
#! /usr/bin/perl -w
use strict;
sub two {2}
printf "two + 2 = %d\n",two + 2;


john@scan test$ ./two.pl 
two + 2 = 2

testing:
printf "%d\n",two;  prints 2

Replies are listed 'Best First'.
Re: two + 2 not equal 4!
by toolic (Bishop) on Jul 24, 2010 at 02:09 UTC
    Tip #6 from the Basic debugging checklist: use B::Deparse to see if your code really is what you think it is:
    $ perl -MO=Deparse two.pl BEGIN { $^W = 1; } sub two { use strict 'refs'; 2; } use strict 'refs'; printf "two + 2 = %d\n", two(2);

    So, two + 2 is interpreted as two(2). Instead of evaluating your function, then adding 2, perl treats everything after your function call as a LIST of arguments when you omit the parentheses. From perlsub:

    2. NAME LIST; # Parentheses optional if predeclared/imported.

    While it is legal syntax to omit the parentheses on function calls, it is a good practice to use them, even if your function does not need arguments:

    printf "two + 2 = %d\n",two() + 2;

    As a side note, your code would render better if you replace your "pre" tags with "code" tags: Writeup Formatting Tips

Re: two + 2 not equal 4!
by BrowserUk (Patriarch) on Jul 24, 2010 at 03:00 UTC

    A couple of ways, (that amount to the same thing), to make it right:

    use constant two => 2;; printf "two + 2 = %d\n", two + 2;; two + 2 = 4 sub two () { 2 };; printf "two + 2 = %d\n", two + 2;; two + 2 = 4

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: two + 2 not equal 4!
by sierpinski (Chaplain) on Jul 24, 2010 at 02:13 UTC
    This works correctly too:
    #! /usr/bin/perl -w use strict; sub two {2} printf "two + 2 = %d\n",(two) + 2;
    Parens have precedence.
Re: two + 2 not equal 4!
by ikegami (Patriarch) on Jul 24, 2010 at 13:31 UTC

    So, two + 2 is interpreted as two(2).

    And that's because the following are all the same:

    two + 2 two +2 two(+2) two(2)

    Omitting parens around arguments can lead to weird problems. You've encountered one. You can disambiguate as follows:

    two() + 2 (two) + 2

    You could also add a prototype to two.

Re: two + 2 not equal 4!
by nvivek (Vicar) on Jul 24, 2010 at 05:28 UTC

    If you want to know how it works clearly.You print the array @_ inside your subroutine.@_ is an array which contains the arguments passed to subroutine. If you call the subroutine without using &, then it will pass the data given after two subroutine will be passed.In your case, two + 2 2 will be passed as an argument. In the subroutine, you didn't handle anything with that argument.Then, 2 will be returned from that subroutine.That's why 2 gets printed. If you use &, then 2 from the subroutine will be returned and then it added with + 2 given.Then, it will print 4.

    use strict; use warnings; sub two { print @_; 2 } print "Two=%d\n", two + 2;

    If you want to have the array structure , use Dumper function which is in Data module.

Re: two + 2 not equal 4!
by morgon (Priest) on Jul 24, 2010 at 02:05 UTC
    If you replace your last line with

    printf "two + 2 = %d\n",&two + 2;

    (note the ampersand) you get "two + 2 = 4". So it seems the parser treats your "two" as a bareword and converts it to 0 in numeric context (therefore the result).

    I wonder why this does not procuce a warning though...

      So it seems the parser treats your "two" as a bareword and converts it to 0 in numeric context
      No. A bareword would generate a compile error with strict. B::Deparse shows us what's going on.
Re: two + 2 not equal 4!
by suhailck (Friar) on Jul 24, 2010 at 06:15 UTC
    To make the print statement work as you wrote, change the sub as given below,

    perl -e 'sub two { $_[0] + 2 };print two + 2'

    output:
    4

    ~suhail