Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Re: Re: Seeking Feed back

by orkysoft (Friar)
on Jul 05, 2001 at 13:04 UTC ( #94043=note: print w/replies, xml ) Need Help??

in reply to Re: Seeking Feed back
in thread Seeking Feedback on Chat Program (was Seeking Feed back)

Actually, in my 1200-line Mapster program (currently down), I used constructs like:
if(open FILE, ">$filename") { flock FILE, 2; ... # Write stuff to FILE close FILE; } else { print "An I/O error occurred!"; log_error $!; # Call a sub }
This allows my program to exit gracefully in the unlikely event of an error.

Replies are listed 'Best First'.
Re (tilly) 3: Seeking Feed back
by tilly (Archbishop) on Jul 05, 2001 at 15:58 UTC
    And so you have an error, you know that there is no such file or directory. What then? How does this help in debugging.

    As perlstyle says:

    o Always check the return codes of system calls. Good error messages should go to STDERR, include which program caused the problem, what the failed system call and arguments were, and (VERY IMPORTANT) should contain the standard system error message for what went wrong. Here's a simple but sufficient example: opendir(D, $dir) or die "can't opendir $dir: $!";
    By not including debugging information on your arguments you will make such basic things as a renamed directory painful to track down.

      And as a side-note, something I learned the other day for error handling in system calls :

      system("/usr/bin/scp $file $username\@$host:$remoteFile"); die "System call to scp command failed! : $!\n" if ($? != 0);

      The special variable $? returns a boolean value for success or fail on system calls. So the above snippet performs a reliable "or die" check on your command. A handy one to know, especially as system tends to be a little unreliable in terms of error checking / return values when using a straight die, IMHO.

      Update: as per comments below, not a "boolean" in the strict sense of the word. Call it an "azatoth boolean" :)

      Azatoth a.k.a Captain Whiplash

      Make Your Die Messages Full of Wisdom!
      Get YOUR PerlMonks Stagename here!
      Want to speak like a Londoner?
        Actually $? is not a boolean. As documented in perlvar, it is the return code of the last system call. That is 0 for success, and all else is an error. If the error is under 256, then it is a system error. If the error is over, then divide by 256 and you have the program's return code. The return code of your programs are set by exit, are 0 by default, and are set from $? on a die.

        Unfortunately that means that every program has its own possible meanings for exit codes. Traditionally, however, 1 means "Error, but not an important one" and 2 means "Bad error". For instance rm on my system will return 1 if you don't give it any files to delete, but a 2 if you try to delete something and it can't.

        Nice. I think this could be done even simpler and more readable using unless instead of if !=:
        system("/usr/bin/scp $file $username\@$host:$remoteFile"); die "System call to scp command failed! : $!\n" unless ($?);


        To make errors is human. But to make million errors per second, you need a computer.

      Well, my CGI program was installed in a controlled environment, where errors should be very rare, and users were generally _very_ clueless. I can't just have my program die on them! Instead, my program would skip the file operation in question, but log an error, and display an error message with a possible solution, print out the rest of the page layout, and then end at the same spot the program would normally.

      Maybe it's a matter of taste, but I just don't like the or die construct, it doesn't give me the ability to neatly and readably handle the exception.


      sub display_values_from_file { my $filename = shift; if(open FILE, "<$filename") { # check return value of open flock FILE, 1; while(<FILE>) { print &process_line_from_file; } close FILE; } else { print "The file could not be opened. Please try again later!"; log_error "open $filename : $!"; } } # main program ... # do something print $some_nice_html; display_values_from_file "/foo/bar.baz"; print $rest_of_html_page; # end

      This way, when an error occurs, the user will be informed of the error, and all the links the user would need would still be there.

        I was not commenting on the error being silent or not.

        I am commenting that your initial version failed to log critical information that would make it possible to debug the problem later. And no matter how controlled the environment may be, you are not going to convince me that you won't ever have bugs to track down.

        I am glad that your current example does that better. It does not do it well enough to make me happy, but it is better.

        Here is a better version of the same thing that you have:

        sub ret_read_fh { my $filename = shift; my $fh = do {local *FH}; unless(open($fh, "< $filename")) { log_error("open '$filename': $!"); return; } unless(flock($fh, 1)) { log_error("flock '$filename': $!"); return; } return $fh; } sub display_values_from_file { my $fh = ret_read_fh(shift); if ($fh) { while(<$fh>) { print process_line_from_file($_); } } else { print "Error opening file. Please try again later!"; } }
        Why better? Well suppose that some bright sysadmin gets the idea of having your data mounted from another machine over NFS. (This is not an unreasonable thing for a sysadmin to have reason to do.) With the revised version you will get notified that flock no longer works. With the original version the error would be silent until someone noticed sporadic loss of data over 6 months and thought to wonder why. (At which point you read your code and have no a clue where it could fail.)

        My points?

        1. Don't trust system calls to succeed.
        2. Make sure that when they go wrong you have enough information to debug.
        3. Realistically you have a choice. Make errors fatal, or else encapsulate code which needs to handle errors. After all when you find a new possible cause of errors you do not want handling it to be harder than necessary.
        Also a middle ground to consider is to make errors be fatal, but make sections with fatal error handling be trapped by an eval block. That makes breaking out on large numbers of possible errors easy to implement, while not interfering with your ability to handle the exception for the user.
Re: Re: Re: Seeking Feed back
by Chady (Priest) on Jul 05, 2001 at 15:46 UTC

    what?  if () {} else {} ?

    what about:

    open FILE, ">$filename" or &exit_with_error ('An I/O error occured!', +$!);
    and in your &exit_with_error sub you do more stuff and exit

    just a thought

    He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.

    Chady |

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://94043]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (4)
As of 2018-05-26 20:52 GMT
Find Nodes?
    Voting Booth?