in reply to (jeffa) Re: 'print' puzzle
in thread 'print' puzzle

OK, so if it's a context problem, I can see that scanfile will see that it was called with "wantarray". But why does print think that's an indirect object, even with parens around it?

—John

Replies are listed 'Best First'.
Re: Re: (jeffa) Re: 'print' puzzle
by clintp (Curate) on Nov 13, 2001 at 01:16 UTC
    Make sure that when you say "context", you're not thinking "scalar" and "list" context. Those don't apply here. Read on...
    print FOO $bar;
    Puts the contents of $bar on the filehandle FOO. We're all clear on that.
    print(FOO $bar);
    Does exactly the same thing in a nicely Perl 4-ish way. Perl's parser knows that the first argument to print (regardless of the parens) might be a filehandle which won't be comma-separated from the first thing to be printed. Now:
    print(Package::FOO $bar);
    Falls into the same trap. You're just specifying the package that the filehandle is in. The solutions:
    print +(Package::FOO $bar);
    The + tells the parser that the parens don't go with the print (and therefore the Package::FOO) and they're just grouping. So the parser isn't looking for a filehandle anymore. The Package::FOO gets used with indirect object syntax.
    print(Package::FOO($bar));
    The parser doesn't see a first-argument space-separated from the things to be printed and knows that Package::Foo is Something Else. (Later it'll know it's a function call.)
    print(&Package::FOO $bar);
    Same goes here, the parser doesn't see a filehandle here and knows that it shouldn't go looking here for one.

    I hope that helps. More importantly I hope my lack-of-sleep answer didn't cause more questions than answered...

      Yes that helps. You say that the parens don't affect it. The "if it looks like a function" rule tells it were the parameter list ends, but the determination that the first argument doesn't have a comma after it must come after that.

      So... why doesn't it know that's a function already? The module was "use"d, so it knows what's inside it.

        There are so many exceptions and interpretations to the "if it looks like a function" rule that it's almost more of a pain than a help. Just let it go. To your second comment, it knows that it's already a function but it doesn't matter -- it could also still be a filehandle. Remember you don't "predeclare" filehandles in any way. And Perl's kinda looking for a filehandle there anyway and your function name will suit just fine.
Re: Re: (jeffa) Re: 'print' puzzle
by blakem (Monsignor) on Nov 13, 2001 at 01:32 UTC
    I don't think perl is parsing that as an indirect object... it looks like perl interprets your print call as the two argument form: print FILEHANDLE LIST. I can emulate this with the following code:
    #!/usr/bin/perl -wT use strict; package main; print Mymod::mysub (); package Mymod; sub mysub { '123' }
    Which errors out with:
    print() on unopened filehandle Mymod::mysub at ./parensubtest.pl line 5.

    Interestingly enough, if you swap the two stanzas (move lines 7,8 above 4,5) the error disappears.

    A similiar (but not identical) issue was discussed at Filehandles vs. Packages: And the winner is...

    -Blake

      What you call the "two argument form" is the "indirect object". You can have any number of arguments: print (x,y,z,1,2,3);. The "indirect object" is the special argument that doesn't have a comma after it.

      I agree, writing print Mymod::mysub (); will look like an indirect object per the node you refered to. But why does print (Mymod::sub ()); that is, with parens around it, do the same thing? That is the question I was asking.

        Parenthesis have nothing to do with it because of the way the Perl grammar is defined. From perly.y:
        LSTOP indirob argexpr /* print $fh @args */ FUNC '(' indirob expr ')' /* print ($fh @args */ LSTOP listexpr /* print @args */ FUNC '(' listexprcom ')' /* print (@args) */
        Looks like a typo in the second line, too.

        I'm not sure I agree that this is an "indirect object", though. It looks like the parser's trying to convert anything that looks like a filehandle into a filehandle.

        Ah, guess we we're talking about the same thing... I got confused when you said:
        I can see that scanfile will see that it was called with "wantarray" But why does print think that's an indirect object...
        But scanfile doesn't get treated as a subroutine at all, so I didn't understand where wantarrray comes in to play. See the second stanza below for what I thought you meant by indirect object...

        I don't have an answer for you, but I have yet to find a print statement that Deparses differently depending on the outer parens. I think it might be a red herring, which is why I left them off in my previous example.

        % perl -MO=Deparse -e 'print abc' print abc $_; % perl -MO=Deparse -e 'print(abc)' print abc $_; # when you said 'indirect object' I thought this was # what you thought was going on.... % perl -MO=Deparse -e 'print abc def' print 'def'->abc; % perl -MO=Deparse -e 'print(abc def)' print 'def'->abc; % perl -MO=Deparse -e 'open abc; print abc def' open abc; print abc 'def'; % perl -MO=Deparse -e 'open abc; print(abc def)' open abc; print abc 'def'; % perl -MO=Deparse -e 'print abc:: def' print abc 'def'; % perl -MO=Deparse -e 'print(abc:: def)' print abc 'def'; % perl -MO=Deparse -e 'print abc:: ()' print abc (); % perl -MO=Deparse -e 'print(abc:: ())' print abc (); % perl -MO=Deparse -e 'print abc::def ()' print abc::def (); % perl -MO=Deparse -e 'print(abc::def ())' print abc::def ();

        -Blake