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

Hi Monks,

Can someone tell me why the thrid print is not printing 30 ?

$a = 10; $b = 20; print $a + $b; print $a+$b; print $a +$b;

Replies are listed 'Best First'.
Re: Print not printing
by NetWallah (Canon) on Jun 24, 2005 at 05:22 UTC
    This is invoking the print FILEHANDLE LIST syntax

    If you use warnings;, you would see

    print() on unopened filehandle 10

         "There are only two truly infinite things. The universe and stupidity, and I'm not too sure about the universe"- Albert Einstein

      Yes, but the mystery remains: why isn't this syntax invoked in the expression print $a + $b, which should be syntactically equivalent to print $a +$b.

      the lowliest monk

        It seems this is one of those rare occasions where white space does matter. The parser has to take a guess at what +$b is supposed to be and guesses that a unary + is used. Bug or feature? Depends on how you look at it, I guess :)

        Paul

        As already said, there is room for ambiguity in this syntax. So although whitespace should not be relevant, it is used to disambiguate things.

        It really is a Perl DWIM thing.

        By putting a space before the + and not behind it, you seem to hint to Perl that the + is now a unary plus and automagically the $a now becomes a filehandle.

        CountZero

        "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Print not printing
by tlm (Prior) on Jun 24, 2005 at 05:15 UTC

    I don't have an answer. It's just one more example of perl getting confused by ambiguous syntax. For some reason that I don't understand, when parsing the third print statement, perl chooses to interpret $a as a filehandle (which is not open) and the + as a unary operator. But adding a + in front of the $a as well clears up that confusion.

    % perl -MO=Deparse,-p -e 'print $a + $b;print $a+$b;print $a +$b;print + +$a +$b' print(($a + $b)); print(($a + $b)); print($a $b); print(($a + $b)); -e syntax OK

    the lowliest monk

Re: Print not printing
by aditya.singh (Acolyte) on Jun 24, 2005 at 08:20 UTC
    Hey, looks like you took the hidderperl.com test.
    That's from where I got this question and we had a discussion on Perlmonks-ChatterBox about that. I don't know if they archieve the chats so that you could read it but here is a summary:

    First, most of the people (including Merlyn, atcroft and demerphq) thought the quiz was crap.

    Secondly, this print behaviour appears to be a bug. You can read more about that here.

Re: Print not printing
by fmerges (Chaplain) on Jun 24, 2005 at 10:02 UTC
    Hi,
    In this case, it gets interpretated as print FILEHANDLE LIST and + as unary operator.
    Doing an assigment first, remove the unambiguity.
    $a = $b +$c; print $a;
    or, explicity defining the output handle:
    print STDOUT $b +$c;
    But's is one of this perlish things, I recommend you using spaces, and all the things to make things more clear.
    Regards,
    :)
Re: Print not printing
by halley (Prior) on Jun 24, 2005 at 14:09 UTC
    When in doubt, use B::Deparse.
    U:\proj>perl -MO=Deparse -e "print $a + $b" print $a + $b; -e syntax OK U:\proj>perl -MO=Deparse -e "print $a +$b" print $a $b; -e syntax OK
    As you can see, perl guesses from the whitespace after print and its first argument that you intended a unary plus, instead of an addition between arguments. It then decided that $a must be an object (like a file handle) for object indirect syntax.

    Personally, I wish Deparse was even more clear about that:

    U:\proj>perl -MO=Deparse -e "print $a +$b" $a->print $b;

    --
    [ e d @ h a l l e y . c c ]

Re: Print not printing
by monarch (Priest) on Jun 24, 2005 at 07:53 UTC
    Just goes to show that paranoia and excessive parenthesising is not such a bad thing after all..
      paranoia and excessive parenthesising is not such a bad thing after all..

      Where can you put parens in the statement in question to make it be interpreted as addition printing to the currently selected filehandle? Others here have shown how a plus signs helps, but I haven't seen how parens would.

      What actually avoids this affect from hurting you is having a sane whitespace style — something which has many benefits.

      Excessive parenthesising is, by definition, excessive. Mostly in makes code harder to read for those of us who know (or can guess) the precedence rules — because you have to put effort in matching up the parens and satisfying yourself that they are indeed superfluous; they look so similar to necessary parens that they can't be quickly dismissed.

      Smylers

        I upvoted the previous post because the post author makes a valid point about excessive parenthesising being confusing.

        However two things make parenthesising easier: one, taking advantage of editor features that highlight the matching paren (Emacs does this wonderfully, and I've no doubt that other editors do this as well); two, the knowledge that things can sometimes go very wrong when precedence is just assumed.

        I tend to use more parens that most people.. that's not to say that sometimes I will rely on operator precedence from time-to-time. Although that got me recently when I incorrectly assumed the precedence of the ? : ternary operator.

        Code readability is always important, and if parens are clogging up readability, then indentation and splitting an expression over several lines isn't such a bad thing either.

Re: Print not printing
by anonymized user 468275 (Curate) on Jun 24, 2005 at 12:43 UTC
    It isn't the cause of this problem, but it seems worth re-mentioning (albeit that people have often mentioned this in the past here) that $a and $b are special sort variables which (believe it or not) are not intended to work as say $c and $d would!

    Example of proper use of $a and $b:

    my %monk = (); $monk{ Alice }{ XP } = 130; $monk{ Bert }{ XP } = 17; $monk{ Charles }{ XP } = 20; foreach my $monk ( sort ByXP( \%monk ) keys %monk ) { print "$monk\t$monk{ $monk }{ XP }\n"; } sub ByXP { # NB $a and $b are reserved for sort routines like this # <=> is a special sort operator for sorting by numeric value my $monastery = shift; ( $monastery -> { $a }{ XP } ) <=> ( $monastery -> { $b }{ XP } ); # note that the last line of a subroutine also # renders what is returned by default, although # sort routines even more magical than that! }

      $a and $b aren't that special. The sort built-in uses their package versions (try the code below in main:: to see if it still works), but that's as magical as they get. They otherwise act like any other package variable, and you don't have to be afraid of them. I'd stay away from them because they aren't descriptive variable names.

      #!/usr/bin/perl -l package Foo; $, = " "; print sort { $Foo::a <=> $Foo::b } qw( 1 7 2 0 4 3 6 );

      In your sort call within the foreach, you don't need an argument. :)

      --
      brian d foy <brian@stonehenge.com>
        Well, they're more special than "the variables sort() happens to use". To achieve that handy usage without warnings, Perl exempts $a and $b from declaration checks under strict vars. That means that

        perl -we'use strict; $a = 5; print $a'

        compiles and runs without errors, while

        perl -we'use strict; $c = 5; print $c'

        won't even compile.

        This has bitten me in real life when trying to cut down a test case for closure scoping behavior. My real code was doing different things than my one-liners, and there was NO DIFFERENCE except the variable names. I was tearing my hair out.

        $a and $b are naturals for quick throwaway code; the documentation uses them in examples all over the place. However, $c and $d are much better choices. I find myself completely avoiding $a and $b outside of sort(), just to be on the safe side.

        It's true that $a and $b will work normally; but I suppose I have the philosophy that code should be as self-evident as possible and using $a and $b as ordinary variables is apt to confuse the reader/maintainer.

        -S

        One world, one people