Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

unless vs. bare block

by chayashida (Acolyte)
on May 10, 2012 at 00:44 UTC ( [id://969720]=perlquestion: print w/replies, xml ) Need Help??

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

Why does this work:

unless (open (QTREES, $file)) { print STDERR "WARNING: get_qtrees() can't open $file for filer $fi +ler!\n"; return; };

But this doesn't work:

open (QTREES, $file) or { print STDERR "WARNING: get_qtrees() can't open $file for filer $fi +ler!\n"; return; };

Basically, I'm trying to change a "open or die" command to an "open or do this list of things" command.

I get a compilation error. It looks like it might have to do with the scope of the variables:

syntax error at ~chayashida/Perl/Module.pm line 872, near "return" Global symbol "$filer" requires explicit package name at ~chayashida/P +erl/Module.pm line 880.

I have the code working using the first version, but I'm curious why the second version doesn't work.

Thanks in advance,

Chris

Replies are listed 'Best First'.
Re: unless vs. bare block
by choroba (Cardinal) on May 10, 2012 at 00:49 UTC
    You cannot use or to connect a block. If you need to use a block in place of an expression, use do:
    open QTREES, $file or do { print STDERR "WARNING\n"; return; }

      Oh, I always forget about do!

      Thanks, that answers my question.

      Chris

Re: unless vs. bare block
by eyepopslikeamosquito (Archbishop) on May 10, 2012 at 02:35 UTC

    unless (open (QTREES, $file)) { print STDERR "WARNING: get_qtrees() can't open $file for filer $fi +ler!\n"; return; };
    As a matter of technique, I would write that as:
    open my $QTREES, '<', $file or die "WARNING: get_qtrees() can't open ' +$file' for filer $filer!: $!\n";
    First, note the addition of $! in the error message to tell you why the open failed.

    Rather than returning with a warning, I have used die. Using die is usually preferable to printing a warning and continuing because if the open fails, there is usually little point in continuing (aka fail fast). Note that die throws an exception, so you can always catch that and not exit the program by wrapping the subroutine call in an eval block in the rare case that you want to continue after the open fails. As an alternative, you could first check via -f $file that the file exists and return with a warning if it does not exist and die only if it exists yet the open fails (update: see below and How portable are common $! error codes? for a race-condition-free alternative).

    Using lexical file handles (i.e. my $QTREES above) is better style because:

    • They are local variables and so avoid the generally evil programming practice of keeping state in global variables.
    • They close themselves automatically when their lexical variable goes out of scope.
    • They avoid the confusion of barewords. IMHO, barewords are an unfortunate Perl feature and should be avoided (except when writing poetry).
    Oh and be sure to start your programs with "use strict;" (just in case you are not doing that already).

    Finally, note that I used the three-argument form of open. As for why the three-argument form of open is preferred, the old two-argument form of open is subject to various security exploits as described at Opening files securely in Perl.

      They are local variables and so avoid the generally evil programming practice of keeping state in global variables.
      Generally, avoid the evil practice of being too general. There are lots of cases where it doesn't matter at all, or where other trade offs can be made. Remember, people could have used lexical filehandle references since 5.000, but it wasn't until they autovivified that people actually started to use them on a larger scale. The world didn't burn up in flames in the mean time.
      They close themselves automatically when their lexical variable goes out of scope.
      Yeah, and so will "bare word" handles. You can even limit their scope by using local.
      They avoid the confusion of barewords. IMHO, barewords are an unfortunate Perl feature and should be avoided
      Wait. You're saying we should write &foo and "Module::Foo"->new instead of foo and Module::Foo::->new, because they're barewords, and unfortunate? You're sure you mean this?
      As for why the three-argument form of open is preferred, the old two-argument form of open is subject to various security exploits
      You've no idea where the second argument is coming from. For all we know, there's no problem. Don't scare people.

        Wait. You're saying we should write &foo and "Module::Foo"->new instead of foo and Module::Foo::->new, because they're barewords, and unfortunate? You're sure you mean this?
        No I didn't mean that. My characterization of all barewords as "unfortunate" was inaccurate and I thank you for pointing that out. To be more specific, I detest bareword strings, for example $x = Hello, except when playing golf and writing poetry (when I adore them). Thankfully, "use strict" disallows this particular use of barewords.

        I also dislike bareword file handles, endorsing the point of view expressed in Why the Modern Perl Book Avoids Bareword Filehandles.

        I prefer not to teach beginners about local and dynamic scope, at least not initially. OTOH, I do teach them about my and lexical scope in the very first lesson.

        For an example of the confusion that can be caused by bareword file handles see: Bareword "FILE" not allowed while "strict subs".

        For similar reasons, I feel that beginners should learn three argument open first: there are fewer gotchas and I don't want to overwhelm the beginning Perl user with many different ways to do the same thing. Rather, I prefer to teach them first what is usually the best way of doing something. I am aware that there are strong differences of opinion on this matter as indicated by this long P5P thread.

        Update:

        Don't scare people.
        Don't bully people. :) In his reply, the OP stated: "I haven't had any experience with the three-argument version" followed by "Thanks, I'll check it out". So the net result of my pointing out three-argument open was not to "scare" the OP but rather to improve his Perl knowledge and skill by encouraging him to read about three-argument open and to learn about the specific problems it solves in security-sensitive environments.

      Thanks for your reply. Typically, I've been using the open or die syntax, but other admins have asked that the code continue even when a file is missing. Though I didn't post the surrounding code, it gracefully handles a null return value for the function.

      I haven't looked at the open command in a while, so I haven't had any experience with the three-argument version. I have been using the strict pragma and tainting input (out of habit, from when I first started learning Perl with HTML.

      I guess I haven't checked on it to see if there's a better way to do things now. Thanks, I'll check it out.

        I guess I haven't checked on it to see if there's a better way to do things now. Thanks, I'll check it out.

        Might as well check out the free Modern Perl book, a loose description of how experienced and effective Perl 5 programmers work....You can learn this too.

      As an alternative, you could first check via -f $file that the file exists and return with a warning if it does not exist and die only if it exists yet the open fails.

      But that is a race condition :) The file could become exist after you check with -f

      use Errno ;

      open ... or do { if( $!{ENOENT} ){ warn "Uh oh '$file': $!" ; return; } die "Uh oh, unexpected '$file': $!"; }
Re: unless vs. bare block
by ww (Archbishop) on May 10, 2012 at 02:30 UTC

    choroba's answer should get you past your messages; this comment addresses your approach:

    unless (open (QTREES, $file)) { print STDERR "WARNING: get_qtrees() can't open $file for filer $fi +ler!\n";

    is unnecessarily verbose. In the first example, you could achieve the same end with:

    unless (open (QTREES, $file) or warn "get_qtrees() can't open $file for filer $filer!\n");

    Similarly, in the second,

    open (QTREES, $file) or warn "get_qtrees() can't open $file for filer $filer!\n";
      unnecessarily verbose. In the first example, you could achieve the same end with:

      That's a syntax error:

      $x=1; unless( $x ) or warn 'Erk!';; [syntax error at (eval 11) line 1, near ") or"

      Remember that unless is a 'negative' if, and Perl doesn't support if without a block.

      Ie. In perl, if( cond ) statement must be coded as if( cond ) { statement; }


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      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.

      The start of some sanity?

         warn "can't open ... " unless open ...;
Re: unless vs. bare block
by roboticus (Chancellor) on May 10, 2012 at 10:55 UTC

    chayashida:

    If you don't care what you return, you can simplify it a bit like this:

    open(QTREES,$file1) or return print "foo";

    If you do care, then you can use:

    open(QTREES,$file1) or (print "foo") && return;

    Example:

    $ touch file1; touch file2 $ perl blenge.pl $ rm file2; perl blenge.pl Error opening file2: No such file or directory $ rm file1; perl blenge.pl Error opening file1: No such file or directory $ cat blenge.pl #!/usr/bin/perl use strict; doit(); sub doit { open QTREES, 'file1' or return print STDERR "Error opening file1: +$!"; open RTREES, 'file2' or (print STDERR "Error opening file2: $!") & +& return; }

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://969720]
Approved by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (7)
As of 2024-04-24 09:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found