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

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

This is starting to bother me. I wrote up a perl script and what I had wanted to do was this
$down="false"; open (FH, $log) || $down = "true";
I obviously got an error about trying to mod a scalar value I found a way to get what I wanted by calling subroutines instead;
use vars qw/$down/; $down="false"; open (FH, $log) || &woops($host); if ($down eq "false") { ....send tail of log file... } else { ....send "server is down" } sub woops { ...do some stuff.... $down = "true"; }
I know this may look like a really stupid bit of perl code, I only code perl for my own enjoyment and I've only been doing it since September. What would you folks recommend? Thanks much.

Replies are listed 'Best First'.
Re: open failure code
by tachyon (Chancellor) on Nov 26, 2003 at 23:17 UTC

    Precedence and operator binding is the issue. But...why not just.....

    if (open FH, $log) { ....send tail of log file... } else { ....send "server is down. Perl say $!" }

    Note the error code (string reason) is set in $! if open, print, close, mkdir, unlink.....fail. Internal Perl functions return 1 if they succeed, 0 or undef if they fail. If you want to do the  || $scalar = 'blah' you can do this:

    blah() || do{ $scalar = 'blah'; more_stuff() }

    cheers

    tachyon

Re: open failure code
by cchampion (Curate) on Nov 26, 2003 at 23:25 UTC

    In addition to the useful advice you've got so far, I would like to point out that programming with flag variables is not always a good idea.

    See this discussion on flag variables for more material on this subject.

    HTH

      Excellent advice. Using flag variables is a bad habit I've developed over the last 8 years. Thanks very much for your helpful response, and thanks everybody else. I feel like such an idiot, but at least I'm smarter than I was before.
        Nope, an idiot would have asked "My Perl code doesn't work. Why?" (without anything else, such as code, examples, assumptions, et cetera).
Re: open failure code
by Revelation (Deacon) on Nov 26, 2003 at 23:17 UTC
    It's all about operator precedence. For more information about precedence theory checkout perlop.
    Regarding your specific problem:
    The line  open ($fh,$log) || $down = 'moo'
    is evaluated as (open ($fh,$log) || $down) = 'moo';
    Obviously, open isn't an lvalue function; you can't assign it a value.
    $log = "moooojlfdkafj.txt"; $down="false"; open (FH, $log) || ( $down = "true" ); print $down;
    or
    $log = "moooojlfdkafj.txt"; $down="false"; open (FH, $log) or $down = "true"; print $down;
    work.

    Gyan Kapur
Re: open failure code
by mpeppler (Vicar) on Nov 26, 2003 at 23:18 UTC
    You could do
    open(FH, $log) || do { $down = 'true'; };
    However that's really bad form, IMHO.

    I might do something like this:

    if(open(FH, $log)) { send tail of log file close(FH); } else { ... send server down... }
    ... and there are various other ways of coding this as well.

    Michael

Re: open failure code
by Anonymous Monk on Nov 26, 2003 at 23:38 UTC
    What all these wise monks forgot to tell you is how they arrived at the answer :)
    perl -MO=Deparse,-p $down="false"; open (FH, $log) || $down = "true"; __END__ Can't modify logical or (||) in scalar assignment at - line 2, near "" +true";" - had compilation errors. ($down = 'false'); ((open(FH, $log) || $down) = 'true');
    B::Deparse

      You could also use this type of contruct

      open(FH,"<".$log) ? print "opened\n" : print "unable to open $!\n";
      it's not any better at all just making you aware of another option.


      Grygonos
        Though this works, the ternary operator, like the grep and map operators, should not really be use in void context.
        if (open(FH,"<".$log) { print "opened\n"; } else { print "unable to open $!\n"; }
        is preferred.


        Who is Kayser Söze?