Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Re^6: Non-fatal error handling with Mouse types?

by wanna_code_perl (Friar)
on Oct 02, 2019 at 14:16 UTC ( [id://11106963]=note: print w/replies, xml ) Need Help??


in reply to Re^5: Non-fatal error handling with Mouse types?
in thread Non-fatal error handling with Mouse types?

It's definitely not my standard way of operating. But it made sense in this case, and I'm hardly the first person to do it this way. In fact: https://perldoc.perl.org/perlmodstyle.html#Error-handling-and-messages:

Error handling and messages When your module encounters an error it should do one or more of: Return an undefined value. set $Module::errstr or similar (errstr is a common name used by DBI +and other popular modules; if you choose something else, be sure to d +ocument it clearly). warn() or carp() a message to STDERR. croak() only when your module absolutely cannot figure out what to d +o. (croak() is a better version of die() for use within modules, whic +h reports its errors from the perspective of the caller. See Carp for + details of croak() , carp() and other useful routines.) As an alternative to the above, you may prefer to throw exceptions usi +ng the Error module. Configurable error handling can be very useful to your users. Consider + offering a choice of levels for warning and debug messages, an optio +n to send messages to a separate file, a way to specify an error-hand +ling routine, or other such features. Be sure to default all these op +tions to the commonest use.
Returning a broken/useless object with an “error state” included

But that's also sort of the point. I'm not returning a broken/useless object. All of the errors in question are recoverable, and the object is never "broken" or in any sort of undefined state.

Replies are listed 'Best First'.
Re^7: Non-fatal error handling with Mouse types?
by Your Mother (Archbishop) on Oct 02, 2019 at 14:21 UTC

    That document echoes almost exactly what I said… With the addition of a global/package error state, not an object error state, which is tenable by tradition but also, in my view, inferior to dying with an error object.

      I wasn't planning on chiming in, because I have nothing technical to add. But there seems to be communication cross-purposes here. I think I understand from a high level what wanna_code_perl is trying to get at. Maybe a translation into an (imperfect) real-world analogy will help.

      There's a universe-program that has a dog-object. When the dog eats (input data), it normally incorporates the food into the fiber of its being, affecting what it is and how it behaves (data is incorporated into the object's underlying data). When the dog is fed bad food, Your Mother and 1nickt seem to be indicating the right thing to do is to stop the universe from running, and make the local deity restart the unverse, after correcting it so the dog won't be fed bad food. wanna_code_perl wants the dog to start crying (an instance-level "something's wrong with my data" flag), so that this specific dog's owner (some oversight sub-process or a future call to a subroutine or method) will take notice, and take the dog to the vet to have the stomach pumped and an IV of good nutrients started (ie, fix the bad data).

      Yes, I understand there are plenty of programming situations when being given bad data is sufficient condition to kill the program; but sometimes, the problems are recoverable, so dying seems overkill.

      Moreover, Your Mother seems to be okay with returning "undef with warnings"; wanna_code_perl seems to want the object's state to indicate the problem, rather than just a return value. I don't see how that's fundamentally different. But maybe I've misunderstood something.

      To me, it looked like this conversation needed a different perspective/phrasing from the outside, so it could start moving forward, rather than going in circles. If this doesn't provide that, or is a useless misunderstanding or one or both perspectives, sorry. Feel free to ignore.

      update: if, as 1nickt said here, error-flags are "...only done in case of exception: ... If you want to do that it's of course perfectly fine, but using type constraints is the wrong approach", then maybe someone could provide guidance on how wanna_code_perl could shift perspective from using type constraints to using something else, to mimic the same flow that already worked, but within the realm of what Mouse and OOP-best-practices makes practical. (tried to get update in before anyone commented on mine.)

        I see the underlying problem as the desire to make a system do something the system—Mouse and “type checking” in this case—is opposed to by design and expectation. Sidenote on the stack trace errors: IIRC, stvn, the creator of Moose, and therefore the designer of Mouse, regrets the decision to use full stack errors instead of plain caller errors.

        The philosophical problem I have with the possible solutions and workarounds is $useless_broken_object now exists and is true and the only way to know it’s bad data is to check it. That’s like allowing $number = Number->new("a\0s\0d\0f") and then needing to remember to check $number->is_really_a_number. Any error catching control flow one might prefer is possible. This one just feels, to me, to be counter-productive, counter-intuitive, and likely to result in bugs because developers will forget to check object state.

        I also should have pointed out that the $DBI::errstr / $dbh->errstr pattern cited—while similar, still different at its root—is pretty universally rejected with { RaiseError => 1 } being considered the best practice and most in agreement that the design of DBI is unfortunate overall.

      I respect you. I really, truly have enjoyed reading your posts over the years. But your "worst practice" feedback is the sort of well-meaning post that makes me sad and sucks the fun out of coming here. None of what you've said is new information to me. From my point of view, this is a solved problem: this class interface was decided upon years before I took over this project, and it meets the requirements, so I even kept it during my re-write (that, and TIMTOWTDI, right?). Would I have done it differently if I started with a clean slate? Maybe. Probably, even. But that's not what I came here to ask, and I know you've been around here long enough to understand that. I'm well versed in the relative merits of error handling paradigms (not to mention bikeshedding of said paradigms) and would (seriously!) be more than happy discussing them with you any other time when I'm not already feeling weirdly defensive about an interface I did not design and did not solicit feedback on.

      That invitation goes for you as well, 1nickt.

        You can always code the way you want. Maybe I should have said, “unusual practice that introduces an unfamiliar and fragile error handling pattern,” instead of worst. Perl may be the most ropeful language there is. :P My feedback is 100% intended to help you down the road; and improve the Perlsphere with best practices so it’s taken seriously. I used to bristle at or flat out reject exactly the kind of advice I’m giving so I understand. I feel the bikeshedding implication is unfair; I’m not injecting a personal preference for magenta here and I’m extremely open about my own personal preferences / idiosyncrasies and where they clash with reality.

        "did not solicit feedback on"

        But you did solicit feedback on your attempts to use Moosey type contraints in an update to the code you are undertaking. I stand by my responses; type constraints are for stopping compilation or execution of your program, and if you don't want to stop, don't use a constraint. You mentioned setting $Errstr or similar but that is only done in case of exception: packages that permit the flow to continue use a warning variable. If you want to do that it's of course perfectly fine, but using type constraints is the wrong approach as shown by your attempts and the workarounds you've been provided here.

        So my feeble contributions have all been with the intent of helping you with your original question. Sometimes the right answer to "how do I do this?" is "don't."

        But, did you look at coercions? Wouldn't correcting a bad value be even better than allowing it? Your coercion can also set or emit a warning if the value needs to be coerced in order to meet the constraint ... ?


        The way forward always starts with a minimal test.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11106963]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (4)
As of 2024-04-25 06:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found