in reply to Re: Re: Idomatic Handling of Subroutine Error
in thread Idomatic Handling of Subroutine Error

You're almost there.
# MAIN unless ($result = my_sub() ) { # Now you use $result if it's not 0 } # WRAPPER function sub my_sub { eval { _my_sub(@_) }; if ($@) { return $@; } else { return ''; } } # Actual worker... sub _my_sub { # Do your stuff here. If something fails, do a die with a useful error + message. Otherwise, return 0. # For example ... die "Bad data passed in.\n"; }
You actually do a die which doesn't end your script - it gets trapped by the eval and the string you passed die will be put in $@.

Now, I personally dislike this type of error-handling because 0 is FALSE and non-zero is TRUE. Thus, you have to flip your thinking the way the C libs force you to and say you're calling the function and hope it "fails" for success. (Sorta like a drug screening ...)

Instead, I would something similar. Instead of passing back '' for success, I'd pass back undef instead.

# MAIN if (defined ($error = my_sub()) ) { # Now you use $error if it's defined } # WRAPPER function sub my_sub { eval { _my_sub(@_) }; if ($@) { return $@; } else { return undef; } } # Actual worker... sub _my_sub { # Do your stuff here. If something fails, do a die with a useful error + message. Otherwise, return 0. # For example ... die "Bad data passed in.\n"; }
It seems like a semantic difference, but now your code use TRUE and FALSE the way they intuitively used, to indicate success and failure.

------
We are the carpenters and bricklayers of the Information Age.

Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Replies are listed 'Best First'.
Re: Re: Re: Re: Idomatic Handling of Subroutine Error
by dvergin (Monsignor) on Sep 18, 2001 at 23:53 UTC
    Promising. But can I drop the wrapping sub by eval'ing the 'die' directly? I also need to have a useful returned val on success. With that, I'll need to reverse the return logic. Is there any hope for an approach like this?
    # MAIN unless ($result = my_sub($val1, $val2)) { my $err_str = $@; # handle error based on $err_str } # do wonderful things with $result sub my_sub { my ($param1, $param2) = @_; # do stuff if ($bad_data) { eval {die "bad data"}; # ??? return undef; } # do more stuff if ($useless_param2) { eval {die "useless param 2"}; # ??? return undef; } # finish doing stuff return $useful_result; }
      If you need a useful return value upon success, you're having that one function do too many things at once.

      A function should do one and only one thing, and do it well. It should be simple enough that you can know what's going on simply due to success or failure. Maybe, you need failure to give you more than one option. Hence, the option I suggested above.

      Try and refactor your function so that if it succeeds, that's all the info you need. If you cannot, make it into an object similar to what btrott said in direct response to your original node.

      ------
      We are the carpenters and bricklayers of the Information Age.

      Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        I appreciate your original suggestion and your bringing the focus to bear on 'first principles'. I understand and support the principle of cohesion.

        We may differ on the application of that principle to this case. I submit that "give me a value or tell me why you failed" is sufficiently cohesive and a useful job description for a subroutine. Granted, it is not Functional Cohesion in the strictest sense. But I think it is a common, intuitive, and effective way to foster clear program flow at the level of the call.

        I agree with your comment on btrott's submission and have /msg'ed him to say so. Since my app is already OO, it is the approach I intend to use in this case.

        But not every program is OO and I was simply wanting to build on your very helpful suggestion and see if it might be possible to extend that idea to allow a useful return value while factoring out the wrapper subroutine.

        My question (and it's about time for me to stop yacking and run some test scripts) is whether the   eval {die "error description"}   trick will work and allow me to access $@ back at the call level.

        Thanks again for this exchange. David