Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

use Fatal;

by cLive ;-) (Prior)
on Jan 10, 2002 at 04:12 UTC ( [id://137626]=perlmeditation: print w/replies, xml ) Need Help??

Browsing through the standard Perl modules, I came across this little number. Considering how much we push strict and warnings, wouldn't it be a good idea to add this module to the list? Eg, if you ever post example code at the monastry like this:
open(FILE,'/path/to/file'); print while (<FILE>); close(FILE); ... open(FILE2,'/path/to/file2'); print while (<FILE2>); close(FILE2);
Someone will always add, "Always use strict, warnings and check whether the files opened OK".
#!/usr/bin/perl -w use strict; open(FILE,'/path/to/file') || die $!; print while (<FILE>); close(FILE); ... open(FILE2,'/path/to/file2') || die $!; print while (<FILE2>); close(FILE2);
Wouldn't it be good practice to suggest adding 'use Fatal;' in as an option instead? ie
#!/usr/bin/perl -w use strict; use Fatal qw(open close); open(FILE,'/path/to/file'); print while (<FILE>); close(FILE); ... open(FILE2,'/path/to/file2'); print while (<FILE2>); close(FILE2);
It just looks cleaner to me. A quick SuperSearch doesn't bring up any previous discussions on this, so I just wondered if there's any reason why this little module appears to be rarely used/discussed?

Thoughts anyone?

cLive ;-)

Replies are listed 'Best First'.
(tye)Re: use Fatal;
by tye (Sage) on Jan 10, 2002 at 05:06 UTC

    I've long felt that Fatal (or a module based on Fatal.pm) needed much greater coverage including print, printf, opendir, seek, write, truncate, kill, pipe, bind, connect, listen, send, socket, chown, chmod, utime, etc. without the user having to name any of these (and, personally, I think a failed close should never warrant more than a warning). And should default to only being fatal when in a void context.

    Then we need a single module that rolls this,strict, and warnings (and only optionally diagnostics) together with a short, catchy name so that we can tell initiates to simply add -MAID or use AID; to all of their scripts to catch lots of simple mistakes.

            - tye (but my friends call me "Tye")
      Got it!
      #!/usr/bin/perl use Bulletproof;
      ;-)

      cLive ;-)

      Another problem with the current version is that it only overrides the given functions in the current package, so all modules and embedded packages must also use it to get the functionality you might want.

      #!/usr/bin/perl -w use strict; use Fatal qw/open close/; package Foo; #use Fatal qw/open close/; sub bar { open(FILE,'dfdsadf'); close FILE; } package main; Foo::bar();

      It should at least be a lexically scoped pragma so the above would be fatal without reissuing the use statement. I'm not sure how it could be made to globally overide such functions in all used packages.

        That is what *CORE::GLOBAL::open= coderef is for. And if it only makes things fatal when in a void context, then this shouldn't be much of a problem for module code that doesn't know whether the user might use this or not.

        You can write code that would break in such cases but I don't consider such code to be reasonable so I don't mind. (:

        open( FILE, "< this.txt" ); warn "Can't read this.txt: $!\n" unless defined fileno FILE;

                - tye (but my friends call me "Tye")
      Well, why not throw in taint, a decent assert() function, and a call to your insurance agent to see if you're covered for that. ;)
      Then we need a single module that rolls this,strict, and warnings (and only optionally diagnostics) together with a short, catchy name so that we can tell initiates to simply add -MAID or use AID; to all of their scripts to catch lots of simple mistakes.

      I suggested exactly this (and coded up a prototype) quite a while back, the name I came up with was

      use caution; #or no caution;
      But if you have a look at the responses I recieved on CLPM to my post(I didnt know about Perlmonks at the time) it was to say the least not a popular suggestion. However if you think it is a good idea I can have another look at it, and include 'fatal' with the defaults you suggest and post it here for review. (BTW I even reserved the namespace ex::caution on CPAN, but havent uploaded it yet. sigh.)

      Yves / DeMerphq
      --
      When to use Prototypes?

Re: use Fatal;
by George_Sherston (Vicar) on Jan 10, 2002 at 05:12 UTC
    This sounds like a Good Thing (tm) - cuts down on typing / file size (marginally, but it all helps) and more importantly makes sure I don't forget to do the error checking.

    Looking at the docs, it looks admirably flexible:

    C<Fatal> provides a way to conveniently replace functions which normally return a false value when they fail with equivalents which halt execution if they are not successful.

    As I read it, this means if I have a function 'foo' that sometimes returns false, and I'd like to know about that for test purposes, say, I can do import Fatal 'foo'; Thus where I have
    use Fatal; import Fatal 'foo'; sub foo { my $test = rand; return $test if $test > .5; } my $test = foo(); print $test;
    Each time rand is less than .5, I get
    Can't foo(), $! is "No such file or directory" at (eval 1) line 3 main::__ANON__() called at p.pl line 10
    ... which is better than nothing.

    The only reason I can think of for doing my own error checking is so that I can supply my own useful info about the failure. So for example I probably wouldn't use this for error-checking DBI function calls, because I would want to add $dbh->errstr.

    Thanks for drawing attention to this.

    § George Sherston
      Actually, DBI is where I was thinking of bringing it in, combined with a custom $SIG{__DIE__}, eg:
      local $SIG{__die__} = sub { die ("DBI Error: $DBI::errstr") if $DBI::errstr; die $!; };
      But make sure you explicitly refer to the error (ie, don't use OO method unless method will definitely be in scope in the sub).

      Could be very useful...

      cLive ;-)

        No need to use fatal with DBI. Just set DBI's RaiseError flag to true. You can even use eval() to catch exceptions with it.
(Ovid) Re: use Fatal;
by Ovid (Cardinal) on Jan 10, 2002 at 04:28 UTC

    Update: D'oh! I wonder why "perldoc -f Fatal" didn't come up with anything :) Yes, that's a joke, but I did add the -f in there when I tried it! How embarrassing that such a useful module is part of the standard distribution and I didn't know that. Sigh... Just focus on the Perl 6 comments, will ya? :)

    cLive ;-) wrote:

    Browsing through the standard Pel modules, I came across this little number. Considering how much we push strict and warnings, wouldn't it be a good idea to add this module to the list?

    It kind of sounds like you're saying that Fatal is part of the standard distribution, but I don't think you meant that. I suppose the reason it's not mentioned more often is because many would likely balk at installing a module to check for something that they do anyway.

    I am aware that this has been brought up in relation to Perl 6. Specifically, it sounds like Perl 6 might have a use strict 'system'; pragma which would be equivalent to the following:

    use Fatal qw/:void open close/;

    The above snippet will throw an exception if you try to open or close a filehandle without explicitly checking the return type. I'd like to see that, but I have no idea whether or not it will actually be implemented.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      Actually, it is in the standard distribution I downloaded and compiled today. After ungzipping and untarring stable.tar.gz in the /root directory, slocate finds this:
          /root/perl-5.6.1/lib/Fatal.pm
      
      ...which would seem to suggest it's official enough to count on until the word comes that it's no longer there.
Re: use Fatal;
by Masem (Monsignor) on Jan 10, 2002 at 10:28 UTC
    Generally, yes, given an operation that might fail, you'd like to catch and die on all errors. But there are cases where you maybe want to see if there's failure, but do nothing about it if there is. For example, in the generation of the perlmonk maps, I query a remote server for the cloud images. If the server doesn't respond, I simply ignore it and go on since the maps can be generated without it. On the other hand, if the user list from PM isn't available, then making the maps would be pointless, and I'd want to die there. EG:
    $clouds = get_clouds( $server ); # note no die if ( $clouds ) { $options{ clouds } = $clouds; } $users = get_users( $server ) or die "Cannot connect to user list" if ( $users ) { $options{ users } = $users; } #not neccesary but nice +ly parallel

    So, IMO, it's nearly always better to explicitly state the die condition than to group them into one. While 90% of the time you may not have to worry about special cases, if you find the need to , you'll have to do a lot of code modification in order to get the special case to work.

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    "I can see my house from here!"
    It's not what you know, but knowing how to find it if you don't know that's important

      While 90% of the time you may not have to worry about special cases, if you find the need to , you'll have to do a lot of code modification in order to get the special case to work.

      Most of the items that Fatal is advertised for only return a "success/fail" value so it is completely trivial to handle the 10% cases. If you look at the return value, then the call isn't fatal. If you don't look at the return value, then the call is fatal.

      Calls that return vital information that can also be an error indication aren't as well suited for the type of error handling change that Fatal imposes and so I don't include those in my proposal above. Note that some of the calls do return information, but that information is not vital.

      For example, I don't include fork because there usually isn't much point in calling fork in a void context. Since you pretty much have to check the return value from fork (to decide if you are now the parent or the child), you usually also manage to check for the error case. The value returned by fork is "vital".

      Now, some invocations of open can return interesting information, such as a process ID. But that information isn't vital. It is very common to check the return value of open only for whether it failed or not. And people (unfortunately) often use open in a void context. So making open (in a void context) "fatal" can be a great way to find hidden errors.

              - tye (but my friends call me "Tye")
      Excuse my potential ignorance, but I'm wondering - for cases when you want explicit checking, couldn't you trap failures using eval {}? Then this:
      open(FILE1, "<file1"); open(FILE2, "<file2") or die "Can't open file2: $!\n";
      is the same as this:
      use Fatal qw(open); eval { open(FILE1, "<file1"); } open(FILE2, "<file2");
      no?
        That is a very ugly use of eval, IMHO.

        I've nothing wrong with the eval function, but I'm of the opinion that eval should be used for code that might be generated on the fly (most likely from user input), thus implying the dynamic nature of the perl language. Using eval to evaluate code that is already hard written into the code, on the other hand, seems to be a way to get around compiler/strict or other issues. Certainly there are cases where using eval on hard-coded code is necessary to achieve certain results (for example, if you have a function from a module that would die on failure, but you want to catch this), but otherwise, it reminds me of when I saw C or C++ code that was wrapped in pragmas in order to disable certain compiler features to get their badly written code working properly.

        IMO, and I think it will be easier in perl 6, I'd much rather move to an OO-based Exception model as Java has, as it forces you to deal with errors, instead of allowing them to slip. This way, you can deal with errors that might be generated from one part of the code differently than errors from other parts. It does require you to think about these errors from the start, but it ends up improving your overall error-catching of the final program.

        -----------------------------------------------------
        Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
        "I can see my house from here!"
        It's not what you know, but knowing how to find it if you don't know that's important

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2024-04-25 17:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found