On Mon, 24 May 2004, JUANMARCOSMOREN wrote:

> Ed Avis wrote:

> > My feeling is that the truly simple interface would throw an exception
> > with an informative message on error, and then you wouldn't have to
> > manually check the return value for each call.  But this suggestion
> > wasn't well received on the list.

> If you want to throw an exception fine with me, but don't use global
> variables!  I'm not sure the easiest way to work with exceptions in
> perl, but exceptions are not global, they are local to the function.

Exceptions in Perl can be global or local, it depends on where and how
they're defined.  Die, for example, is an exception.  If it is not
caught the program dies.  If it is caught then the the handler can
choose to rethrow it or continue on.  For example:

$SIG{__DIE__} = sub {
        if( $_[0] =~ /not.*serious/i )
                return;
        }
        die @_;
}


die "Not very serious";         # doesn't kill the program
die "Serious";                  # kills the program

This is an example of a global die handler.  Note however that you can
localise die handlers like this by using the local keyword.  This will
limit their scope to the block they're in and all subroutines and
functions called from within that block, just like localising Perl's
special variables.

The big problem with using die handlers (also cooked hooks) is that it's
action from a distance.  It's great if you want this action but hard to
avoid otherwise.  This usually leads to careful crafting of your error
messages to provide more useful state information.

A very local die handler can be used by using eval:

eval {
        function();
        die "Not very serious";
        function2();
}
if($@) {
        unless( $_[0] =~ /not.*serious/i )
                die $@;
        }
}

The very first thing to die in an eval block like the above terminates
the eval block.  If function() throws its own exception (calls die) then
we won't get to the explicit die call.  Whatever happens we will never
get to the call to function2() even though the message isn't serious.

Ed Avis appears to be asking for the LWP::Simple functions to die on
failure rather than return a false value.  The advantage to this method
is that instead of writing:

do_this() or die "can't do_this...";
do_that() or die "can't do_that...";
do_this_other_thing() or die "can't do_this_other_thing...";
do_something_else() or die "do_something_else()...";

the programmer merely writes:

eval {
        do_this();
        do_that();
        do_this_other_thing();
        do_something_else();
}
die $@ if $@;

This means that the first thing to die ends the eval block.
This is a much cleaner interface but involves a mental paradigm shift
from the check all return values style of thinking.

> > You make a good point about global variables, however I felt it was
> > overridden by the importance of usable error reporting.  The global $!
> > for error messages is rather ugly, but still any good beginner's Perl
> > tutorial recommends to always put $! in every error message.
> DO NOT USE GLOBALS!!!
> If a tutorial tells you to use a global variable then that's a bad
> tutorial!

I'm not sure whether you read Ed's paragraph fully.  I'm sure that
you're not suggesting that Perl programmers should avoid using the
special variable $! just because it is global?

I do agree that introducing globals is a bad idea, even to handle usable
error reporting.  Perhaps there's a better solution for this problem...
although I get the impression that your solution would be not to use
LWP::Simple, and maybe that is a better approach.

For what its worth, I understand that changing the behaviour of a well
used library from relying on return values to using exceptions is
ludicrous.  Short of introducting a package variable (or object value)
which changes the behaviour (to turn on exceptions) I'm not sure what
the correct behaviour should be here.  DBI does this, you can have
RaiseError set to true for exceptions or false for non exceptions.  I
suspect the code would then become similar to:

sub something {
        my $self = shift;

        # stuff

        if( $error_situation ) {
                return 0 unless $self->{use_exceptions};

                my $subname = (caller(0))[3];
                die "$subname: $error_situation";
        }
}

Although there might be a nicer way of doing it.

All the best,

        Jacinta Richardson

--
   ("`-''-/").___..--''"`-._          |  Jacinta Richardson         |
    `6_ 6  )   `-.  (     ).`-.__.`)  |  Perl Training Australia    |
    (_Y_.)'  ._   )  `._ `. ``-..-'   |      +61 3 9354 6001        |  
  _..`--'_..-_/  /--'_.' ,'           | [EMAIL PROTECTED] |
(il),-''  (li),'  ((!.-'              |   www.perltraining.com.au   |


Reply via email to