Beefy Boxes and Bandwidth Generously Provided by pair Networks Joe
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Re^11: eval to replace die?

by BrowserUk (Pope)
on Oct 06, 2010 at 21:18 UTC ( #863868=note: print w/ replies, xml ) Need Help??


in reply to Re^10: eval to replace die?
in thread eval to replace die?

You're assuming that the only reason to catch an error is to try to fix it. There are lots of other reasons, like ignoring it, changing the error message for a different audience, etc.

Actually, I didn't make that assumtion. In the next para down I said:

If they are further back up the call hierarchy, all they can do is report the error (or ignore it), and they don't need to parse the error message, it already contains the relevant information.

I didn't mention the "switch error message" explicitly, and I won't bore you with how easy that is to do with eval and die.

Though I could make an extensive case for NOT dumbing down error messages for "the user". If the error is important enough to report, it's important enough to ensure that when the user reports the error back to the developers, it contains enough information to allow you to do something about it. Without having to ask the user to toggle some config or command line switches and then try and reproduce the error before you can begin to address it.

But that's an argument for another time.

And the really nice thing about Exception::Class is that if you don't care about all the extra goodies it provides, then just ignore it an treat it like a string and leave the rest of us alone.

I'd ask you to re-read all my posts in this thread, but you won't, so you'll have to take my word for this.

The bit that everyone seems to have missed, is that I have never once said that anyone should not use Exception::Class. Never, not once.

My original thrust was, that having a diagnostic tool with the default set to flag all uses of the block eval & die exception handling mechanism, as "verbotten", is stupid. And that the justifictions cited in support of that were--and are--bogus.

I followed that with the assertions--that I maintain--that :

  1. Exception::Class doesn't avoid string comparisons, it just moves them elsewhere;
  2. That the implementation of E::C means that the number of error vectors due to typos, is actually greater than with eval & die;

    This because the number of different places where the name of the exception has to be supplied, as a string, which are therefore not checked or cross-referenced in any way by the compiler.

    And because package names are stored as hash (stash) keys, they are also not subject to compile-time checks. (strict & warnings).

Indeed, I have, do, and will continue to prefer exceptions to error returns for most code in most languages I use, including Perl. And having discovered Try::Tiny, I'll probably use that in preference to eval & die in future. Where warranted.

I seriously doubt that I will ever use or recommend E::C--because of the way it bypasses compile time check through the use of strings--but I would never for one instant try and stop anyone else from using it. Though I might again point out its weaknesses to newcomers to that module. Beyond that, it is up to them.

So, I'll hope you'll see that I'm not the one being unreasonable here. I'd really like to move beyond the he said/she said stage and get to the point where we could do the pragmatic thing of comparing the failure vectors of concrete code. I've invited same, without response.

Apparently, there are some 60 modules out of the 18,000+ on CPAN that use E::C, but try as hard as I might, I have still to find a simple, complete, worked example of its use. The synopsis snippets don't form a working example, and the (lack of) diagnostics mean that I've failed to get my attempt, posted near the top of this thread, to work.

I'm not a newbie, and I have a track record of getting difficult stuff to work, but so far it has defeated me. The lack of any working examples posted in response to my request make me conclude that perhaps others have similar problems.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.


Comment on Re^11: eval to replace die?
Re^12: eval to replace die?
by mithaldu (Monk) on Oct 08, 2010 at 12:32 UTC
    > Exception::Class doesn't avoid string comparisons, it just moves them elsewhere;

    I think this is a misinterpretation on your side.

    Chromatic is not arguing against string comparisons per se, but against converting complex structures (errors) into strings which then need to be parsed back into complex structures in other places. He is arguing against this in comparison to the possibility of just passing complex structures as they are and only convert them to strings when actually needed.

    E::C is really only one way to do it. Just plain throwing hashes as exceptions makes things nicer because you can add things to them without any risk of breaking regexes when converting back to a complex structure on inspection.

    At least that's how i read what he's saying.

    As far as a workable example goes, what would be wrong with this: http://gist.github.com/616705 (updated to be more amenable to classic perlers)
      I think this is a misinterpretation on your side.

      Chromatic is not arguing against string comparisons per se, but against converting complex structures (errors) into strings which then need to be parsed back into complex structures in other places.

      And I think that misinterpretation lies elsewhere. I do understand Chromatic's point, but I think my point is equally valid. If not stronger as it happens earlier in the scheme of things: that is, earlier in the execution order.

      Take this

      use Exception::Class ( 'MyException', ^^^^^^^^^^^ + #1 'AnotherException' => { isa => 'MyException' }, ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ + #2 & 3 'YetAnotherException' => { ^^^^^^^^^^^^^^^^^^^^ + #4 isa => 'AnotherException', ^^^^^^^^^^^^^^^^ + #5 description => 'These exceptions are related to IPC' }, 'ExceptionWithFields' => { ^^^^^^^^^^^^^^^^^^^ + #6 isa => 'YetAnotherException', + #7 ^^^^^^^^^^^^^^^^^^^ fields => [ 'grandiosity', 'quixotic' ], alias => 'throw_fields', }, );

      There are seven, unchecked points of failure in that small sample. Those strings eventually end up in the symbol table, which is a hash.

      Later, when the exceptions are thrown; and later still when they are caught and isolated, a lookup into symbol table will be done to find them--and that is a string comparison.

      If there are typos in any of those 3 places; or if the exact name of one of them is changed, accidentally or deliberately at some later point in the development or maintenance cycle; then a mismatch occurs. But because they start life as strings, those errors won't show up until runtime. As these are by definition, only exercised in exceptional circumstances, that could be months or even years later before the mismatch is discovered in production.

      Now, as this is Chromatic we're talking about, I'm sure--had he not disengaged(*)--that he would argue that those failure paths should be exercised during pre-production unit & systems testing. And he would be right.

      But exactly the same holds true for any failures in the parsing of exception strings! In both cases, either the code is tested and errors are caught before production; or they're not and they turn up in production.

      And when the mismatch is detected, there will be just as many places to change in the E::C class code as in the string error code--assuming equal diligence to the DRY principle on behalf of both developers.

      E::C is really only one way to do it.

      That was the original basis of my contention. eval & die is a legitimate other way; that has been acceptable to Perl programmers for the best part of 20 years; and is used, where needed, by 18,000+ (-60 that use E::C) CPAN modules.

      I've no objection to people re-inventing the wheel, but mandating change for change's sake, is intolerable.

      Recommending a heavy & broken(see below) replacement, even worse.

      Just plain throwing hashes as exceptions makes things nicer

      That's fine--if you actually need complex structure--which is debatable. But does no one see how easy and lightweight that can be done:

      eval{ die { a=>b=>c=>d=>}; } or print %{ $@ };; c d a b
      because you can add things to them without any risk of breaking regexes

      I think that I've demonstrated above that the "risk" is no greater that with E::C, if you assume equally diligent developers and testing regimes. To assume otherwise is either naive or prejudicial.

      when converting back to a complex structure on inspection

      And this is the final sinew on my bone of contention. Why do you need structured information to deal with an exception?

      If you are going to deal with by trying to 'fix' it, then you will (should) be at a point in the code where you already have access to all the required information to do so. There should *never* be an occasion when the failing routine has to pass you information to deal with an exception that you don't already have access to. After all, you called the routine and passed it the relevant information!

      And if you are going to deal with it by reporting an error; you only need to log the string form anyway. The most you need to do is prefix it with something like:

      An error occurred.

      The following information probably won't mean anything to you, but it will greatly help our developers to provide you with a quick solution. Please report it accurately.

      blah...

      Or, if you feel the need to keep the technical details from your customers, display a "user friendly" message of the form:

      An error has occured. Please pass the full details, from error message timestamped: "yyyy-mm-dd hh:mm::ss Error123" in the program log, verbatim to our developers, along with as much other information as possible, for a speedy resolution.

      and log the text of the exception.

      Most of the time, I see no technical reasons to extract complex information from an error message. And that really squashes the main argument for structured exceptions. Which makes mandating their universal use nothing more than jumping headlong on the Java-esque bandwagon and pandering to the latest fad.

      As far as a workable example goes, what would be wrong with this: http://gist.github.com/616705

      Um...apart from that it wasn't available until 5:30am today, which means my searches--nor anyone else's--could have found it at the point I did my searches; it uses Try::Tiny. Which may be a good way to do it, but isn't mentioned in the E::C synopses, and essentially throws away the purpose of half the code including two of the dependencies of E::C.

      The module synopsies use:

      # catch if ( $e = Exception::Class->caught('MyException') ) { warn $e->error, "\n", $e->trace->as_string, "\n"; warn join ' ', $e->euid, $e->egid, $e->uid, $e->gid, $e->pid, $e +->time; exit; } elsif ( $e = Exception::Class->caught('ExceptionWithFields') ) { $e->quixotic ? do_something_wacky() : do_something_sane(); } else { $e = Exception::Class->caught(); ref $e ? $e->rethrow : die $e; }

      Which to the best of my abilities, simply doesn't work!

      (*) And I take his early disengagement from this discussion, to mean that these realities have dawned upon him also.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        Alright, i'll give it one more try to see if i can get through to you. Here's how the situation looks like to me:

        <chromatic> errors like "Error:ID:001|description|extradata:eins,zwei,drei" are terrible, because if you parse them with regexes, shit is hilariously easy to break in ways that are hell to debug or worse, you won't even NOTICE
        <BrowserUK> but with exception objects you still have to compare strings, SO THERE!
        You completely miss the crucial difference between a simple string comparison and a regex to deparse something. The former is fine because that's what perl even does when calling builtins, because they are ALSO in a hash table. The latter is a nightmare when you're dealing with inputs that are bound to change.

        That was exhibit one. But there is more to come.

        Um...apart from that it wasn't available until 5:30am today
        The module synopsies use: ... Which to the best of my abilities, simply doesn't work!
        My example is a cut-down version of the synopsis, with some things changed to make it more readable for perl developers who are really adverse to thinking about things. Furthermore, the synopsis works. You can dump it into a .pl file, add a hashbang at the top and execute that and it will just plain work.

        Have you even tried that or did you let your prejudices guide you?

        essentially throws away the purpose of half the code including two of the dependencies of E::C.
        E::C's code consists of two files:
        Class.pm - a factory for exceptions
        Class/Base.pm - a base class with all the things exceptions can do

        Its depencencies are:
        Class::Data::Inheritable = 0.02
        Devel::StackTrace = 1.20
        Scalar::Util = 0
        perl = 5.008001

        So, seriously, what the hell are you talking about? Neither of this has an overlap with Try::Tiny.

        There should *never* be an occasion when the failing routine has to pass you information to deal with an exception that you don't already have access to. After all, you called the routine and passed it the relevant information!
        You have never worked in a team where components are written by different people.

        eval & die is a legitimate other way; that has been acceptable to Perl programmers for the best part of 20 years; and is used, where needed, by 18,000+ (-60 that use E::C) CPAN modules.
        Do you think Justin Bieber is an amazing artist and provides rich value to the human culture? (Hint: Appeal to popularity is a fallacy.)
        But does no one see how easy and lightweight that can be done: die %hash
        Yes, i did that for a while. It's nicer than strings, for reasons explained at the top, but it's also a bit clunky and makes you type a lot of stuff. I ended up having to boilerplate a lot when throwing exceptions like that, so having a module that provides a bunch of that kind of stuff in one is neat.

        Now, one point i have to concede: The API for E::C is a bit atrocious, and forces you to also do a lot of boilerplating. Thus: http://www.reddit.com/r/perl/comments/domue/rfc_simple_callerbased_exception_creation/
        I take his early disengagement from this discussion, to mean that these realities have dawned upon him also.

        Not in the least; I tired yet again of wiping your spittle from my screen. The word mandate? I assure you: I look nothing like Moses and I have no stone tablets in my office.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (7)
As of 2014-04-21 11:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (493 votes), past polls