The recent thread on Expectuations brought back to mind something I've been
thinking for a while.  In short, I propose that "use fatal" be on by default, 
and
that "err" be turned into syntactic sugar for a very small try/CATCH block.

Basically, my observation is that no-one consistently checks the return values 
of
the built-in functions.  As Mama[1] can attest, lots and lots of code is posted 
to
Perl Monks calling open without checking the return value.  Even among those who
check the return value of open, just about none check for close[2].  And have 
you
*ever* seen a program that actually checks the return value of print[3]?

Exception handling seems to provide a good solution to this.  Instead of writing
"open ... or die ..." every time, we can just blindly assume the open worked, 
and
catch the error later.  If we don't catch it, it does exactly what the "die" 
would
have anyway, so we're no worse off.  The exception propagates upwards until it's
handled, or it terminates the program.  At least the program doesn't continue
blindly, believing all to be well.  The problem with typical exception handling
code is that it quickly becomes bulky and ugly.  Compare.

#ignore any files we don't have access to
for @files {
  my $fh = open $_ or next;
  load_config_from($fh);
}

with

#ignore any files we don't have access to
for @files {
    my $fh;
    try {
        $fh = open $_;

        CATCH {
            next;
        }
    }
    load_config_from($fh);
}

So returning a special value makes checking the return code simpler, but hurts 
us
if we forget.  Throwing an exception saves us from forgetting, but has the
nastiness of catching that exception.

I propose that the spelled out version of // be renamed to something like "dor".
(I'm willing to accept other suggestions on that.)  "err" becomes a
single-expression level try/CATCH block.  The left hand side is executed, and 
if it
successfully returns anything (even undef), it's value is used.  If it throws an
exception, however, that exception is caught and the right hand side is 
evaluated
and used.  So that code becomes

for @files {
    my $fh = open $_ err next;
    load_config_from($fh);
}

which is just syntactic sugar for

for @files {
    my $fh = try {
        open $_;

        CATCH {
            next;
        }
    }
}

"err" would bind tighter than assignment, so it can be used to provide a 
fall-back
value to use in case the normal flow of control fails.  Using "no fatal" is 
still
allowed, but you can achieve almost the same thing [4] by adding "err $! but 
undef"
after calls whose failure you want to handle that way.

I think on the whole this gives us a way to allow exceptions to be used 
everywhere,
while making it clean and simple enough that it doesn't bog us down too much.



[1] http://www.perl.com/pub/a/2005/09/22/onion.html?page=6
[2] I've actually seen data lost due to this.  When drive space is very limited
(due to, for instance, a user quota) it's often possible to open a new file 
(since
there's some space left), but the close fails since too much was written to it.
[3] Actually, I'm not sure this is fair.  It seems that, due to buffering and 
other
things, print returns true even when it doesn't actually succeed.  But why let
facts get in the way of rhetoric?
[4] The difference is that "no fatal" would only affect code that calls "fail"
itself.  The "err" would affect code that directly calls "die", too.
--
Adam Lopresto
http://cec.wustl.edu/~adam/

Eschew obfuscation!

Reply via email to