in reply to Best way to handle readline errors?

Working on the basis of $! is "russian-roulette" with you guaranteed to lose everytime, it's value can be anything when the expression it is associated with succeeds.
$ perl -le 'print $c++ for 0..0xFFFF' > test; ls -l test -rwxr-xr-x 1 user user 382106 2006-11-14 15:04 test $ perl -e 'open F, "test"; print "$! => $_" while <F>' Bad file descriptor => 0 Bad file descriptor => 1 Bad file descriptor => 2 ...
Infact, undefining $! has no effect and perlvar does say "the value of $! is meaningful only immediately after a failure". Like $^E, its useful for one thing only - describing the error that occured. Programming around it would definitely be considered "bad practice".

Just use defined or eval to test the success of readline().
#!/usr/bin/perl -Wl use strict; use warnings; $|++; open F, "<", $ARGV[0]; while (1) { last if eof(F); if (defined chomp( local $_ = readline (F) )) { print } else { warn "hmerrm, readline failed : $!"; last; } } # or while (1) { last if eof(F); chomp( local $_ = eval "readline (F)" ); unless ($@) { print; } else { warn "whoops, readline failed : $@"; last; } }

Replies are listed 'Best First'.
Re^2: Best way to handle readline errors?
by jrw (Monk) on Nov 15, 2006 at 13:32 UTC
    Firefly258, are you saying that perldoc readline is wrong? From perldoc readline:
    for (;;) { undef $!; unless (defined( $line = <> )) { die $! if $!; last; # reached EOF } # ... }
    That clearly indicates that EOF and a readline error can be distinguished by undefining $! before the call and then, if readline failed, checking if $! is set to non-0.
      I should have said this before to make it a little clearer.

      Read the contents of $! to glean the exact cause of an error right after an unsuccessful operation, Do not test $! to determine the success of an operation, use the TRUE/FALSE value returned instead. The Menmonic of $! is -- "What just went bang?" not "Did I just hear bang?", There is an obvious difference.

      Your reading of the operation concerning $! is definitely right but the reading concerning the context in which it is done is not. Here, if <> returns undef to $line, defined returns FALSE to unless () which puts the execution control in its block, it is there and only there where $! is current and valid.

      E.g
      unless (defined( $line = <> )) { die $! if $!; # $! is only current and valid in the afterma +th of a failure last; # reached EOF }
      is not the same as
      $line = <>; if ($!) { print "Ohh noo, $!"; # an indefinite false-positive }
      if you should ask why?? Consider the following..
      $ touch test; # create the dummy $ perl -Mstrict -Wle 'undef $!; open my $fh, "<", "test" or warn "warn + : $!"; print "after : $!"' after : Inappropriate ioctl for device $ rm test; $perl -Mstrict -Wle 'undef $!; open my $fh, "<", "test" or warn "warn +: $!"; print "after : $!" warn : No such file or directory at -e line 1. after : No such file or directory
      In the first operation, open succeeds and returns a TRUE value so warn() is skipped. However in the second, open fails and returns FALSE, warn is triggered spitting out a valid $!. The $! outside the expression is not trustworthy as one would infer from the documentation of $! in perlvar.

      update

      a readline error can be distinguished by undefining $! before the call

      undefining $! is a useless, almost redundant operation IMO, consequetive operations will set $! if they need to, sometimes regardless of whether they succeed or fail.

      checking if $! is set to non-0

      It's more like, checking if $! is TRUE, because FALSE can be representation of not just 0 but undef, "" (blank) or "0";
        I don't think we're disagreeing on the use of $! only after a failure (i.e. only after a check of the result from readline for definedness).

        However, it's critical that $! be "emptied" (set to a FALSE value) before calling readline, if $! is to be used to distinguish between EOF and a read error, as the code from perldoc readline does.