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

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

Every once in a while I mistype someting like:
open(F, "<$somefile") || { print "Could not open file\n"; exit 3; }
which results in a syntax error. I've always wondered why this isn't allowed to work. Does anyone have a link to a discussion of why this is? Or a quick dissertation on the topic that can be cut and pasted in? Of course there are lots of ways to work around this, no need to explain, the most obvious being
if (! open(F, "<$somefile")) { print "Could not open file\n"; exit 3; }
Being a Perl true believer I disdain a C-ish expression when someing more Perlish is possible ... Thanks, --w

Replies are listed 'Best First'.
Re: Looking for discussions of "block after or" syntax error (hash vs block)
by LanX (Saint) on May 01, 2013 at 18:37 UTC
    > I've always wondered why this isn't allowed to work.

    because of the ambiguity of literal hashes and blocks, the parser can't tell what you mean between curlies w/o heuristics. For instance from time to time people are very confused why map doesn't work like they thought.

    That's why Perl6 introduces < > for hashes.

    You either need to ...

    • put a do in front of your { block },

    • or use a comma as statement separator.

       open(F, "<$somefile") || print("Could not open file\n"), exit 3;

    But keep in mind, the if() solution you showed is the most readable for most programmers.

    > Does anyone have a link to a discussion of why this is?

    e.g. Re: map problem or Re: map syntax error -- weird

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: Looking for discussions of "block after or" syntax error
by tobyink (Canon) on May 01, 2013 at 19:34 UTC

    The keyword you're looking for is do...

    open(F, "<$somefile") or do { print "Could not open file\n"; exit 3; };
    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
      Thanks for all the quick replies... I have never really used "do" in Perl for some reason, so I've forgotten about it!
Re: Looking for discussions of "block after or" syntax error
by Laurent_R (Canon) on May 01, 2013 at 20:11 UTC

    A possibly more perlish way:

    my $in = "somefile.txt"; open my $FH, "<", $in or print "cannot open file $in\n" and exit 3;

    EDIT: I had not paid attention to your title when I wrote the above, I now see that your question is really related to the block construct after the or keyword. My answer above may thus be slightly off-topic. It still gives a workable solution to the immediate problem and probably a better syntax to open a file.

      print returns false on failure, in which case the 'and' would short-circuit and exit would never get called.

      Granted, it's pretty unusual for print to fail -- so rare that we rarely test for success in our prints, and usually don't think in terms of "this could fail", but when you absolutely positively want to exit, don't include a logical test on print's success.


      Dave

        Agreed. I did not think about that. And I usually don't do such a print anyway but rather a die statement (although, going to the end of this logic, what do you do if die fails? Do you 'die "i failed" or die "die failed"'?

        Usually, the only reason I want to know that opening a file failed if to get an immediate diagnostic of the reason for the program failure. If the print statement fails, well, I am likely to have more severe problems than just file opening.

      Maybe a matter of taste, but do you think the precedence rules of or and and are that obvious, that this code is immediately understood?

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        Yes, I agree with you, Rolf, it is true that there might be a problem of understanding, but the construct is so practical that that I think it is worth the effort. Besides, it is easy to force precedence with parens:

        open my $FH, "<", $in or (print "cannot open file $in\n" and exit 3);

        so that, in fact, replacing curlies by parens in the OP's code might really be all that is needed to make it work if I did not miss anything (I haven't tried it in real context).

        Besides, as far as I understand it (but I may be wrong on that, I haven't investigated very far), it seems to me that it is not really a issue of precedence between the operators, but a simpler question of left to right Boolean evaluation with the right part of the expression simply not being evaluated if not needed (i.e. if the left part is true with an "or" operator, or if the left part is false with an "and" operator).

        Consider these two one-liners (I have an xml.pl file in my current directory, but no xml2.pl):

        $ perl -e 'open my $FH, "<", "xml.pl" and print "Opened!" or print "ca +nnot open file\n" and print 3' Opened! $ perl -e 'open my $FH, "<", "xml2.pl" and print "Opened!" or print "c +annot open file\n" and print 3' cannot open file 3

        This seems to work fine in both cases. I am of course not suggesting that such bizarre code should really be used for anything useful, but I am just pointing out that this would not work, I think, if we were to rely on the fact that the "or" operator has a lower precedence than the "and" operator.

        Especially considering the Perlish idiom for this situation is die which inherently combines print and exit.

        As Occam said: Entia non sunt multiplicanda praeter necessitatem.