What's broken about exceptions in Perl?

前端 未结 8 1170
孤城傲影
孤城傲影 2020-11-30 05:43

A discussion in another question got me wondering: what do other programming languages\' exception systems have that Perl\'s lacks?

Perl\'s built-in exceptions are a

8条回答
  •  臣服心动
    2020-11-30 06:09

    Some exception classes, e.g. Error, cannot handle flow control from within try/catch blocks. This leads to subtle errors:

    use strict; use warnings;
    use Error qw(:try);
    
    foreach my $blah (@somelist)
    {
        try
        {
            somemethod($blah);
        }
        catch Error with
        {
            my $exception = shift;
            warn "error while processing $blah: " . $exception->stacktrace();
            next;    # bzzt, this will not do what you want it to!!!
        };
    
        # do more stuff...
    }
    

    The workaround is to use a state variable and check that outside the try/catch block, which to me looks horribly like stinky n00b code.

    Two other "gotchas" in Error (both of which have caused me grief as they are horrible to debug if you haven't run into this before):

    use strict; use warnings;
    try
    {
        # do something
    }
    catch Error with
    {
        # handle the exception
    }
    

    Looks sensible, right? This code compiles, but leads to bizarre and unpredictable errors. The problems are:

    1. use Error qw(:try) was omitted, so the try {}... block will be misparsed (you may or may not see a warning, depending on the rest of your code)
    2. missing semicolon after the catch block! Unintuitive as control blocks do not use semicolons, but in fact try is a prototyped method call.

    Oh yeah, that also reminds me that because try, catch etc are method calls, that means that the call stack within those blocks will not be what you expect. (There's actually two extra stack levels because of an internal call inside Error.pm.) Consequently, I have a few modules full of boilerplate code like this, which just adds clutter:

    my $errorString;
    try
    {
        $x->do_something();
        if ($x->failure())
        {
            $errorString = 'some diagnostic string';
            return;     # break out of try block
        }
    
        do_more_stuff();
    }
    catch Error with
    {
        my $exception = shift;
        $errorString = $exception->text();
    }
    finally
    {
        local $Carp::CarpLevel += 2;
        croak "Could not perform action blah on " . $x->name() . ": " . $errorString if $errorString;
    };
    

提交回复
热议问题