The answer to your question is extremely difficult, and I'm not even going to field it because its a poor solution to your real problem. What's the real problem? The problem is that you want an error inside a deeply nested subroutine call to bubble up the stack. This is what exceptions are for.
Here's your code rewritten to throw an exception using croak
.
package X;
sub new {
my $class = shift;
my %args = @_;
my $obj = bless \%args, $class;
$obj->check_size;
return $obj;
}
my $Max_Size = 1000;
sub check_size
{
my $self = shift;
if ($self->{size} > $Max_Size) {
croak "size $self->{size} is too large, a maximum of $Max_Size is allowed";
}
}
Then when the user creates an invalid object...
my $obj = X->new( size => 1234 );
check_size
dies and throws its exception up the stack. If the user
does nothing to stop it, they get an error message "size 1234 is too
large, a maximum of 1000 is allowed at somefile line 234"
. croak
makes sure the error message happens at the point where new
is
called, where the user made the error, not somewhere deep inside X.pm.
Or they can write the new() in an eval BLOCK
to trap the error.
my $obj = eval { X->new( size => 1234 ) } or do {
...something if the object isn't created...
};
If you want to do something more when an error occurs, you can wrap
croak
in a method call.
sub error {
my $self = shift;
my $error = shift;
# Leaving log_error unwritten.
$self->log_error($error);
croak $error;
}
my $Max_Size = 1000;
sub check_size
{
my $self = shift;
if ($self->{size} > $Max_Size) {
$self->error("size $self->{size} is too large, a maximum of $Max_Size is allowed");
}
}
The exception from croak
will bubble up the stack through error
, check_size
and new
.
As daotoad points out, Try::Tiny is a better exception handler than a straight eval BLOCK
.
See Should a Perl constructor return an undef or a "invalid" object? for more reasons why exceptions are a good idea.