Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^9: eval to replace die?

by BrowserUk (Pope)
on Oct 05, 2010 at 02:04 UTC ( #863493=note: print w/ replies, xml ) Need Help??


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

Just one example is that isa() knows how to look up the inheritance tree

Actually the built-in isa() only checks one level. UNIVERSAL::isa() does a hierarchy traversal--which is a hash lookup. And a hash lookup is just a string compare at it's heart.

But if you're using eval & die you don't need isa, so the point (in context) is moot.

Chromatic suggested that using exceptions avoided "unreliable string comaprisons, substring comparisons and regexes". Which it doesn't. It just moves them.

I have to parse that string with regular expressions to get the $cmd and $server values, every place it could be used

Why do they have to parse the string? (Ie. Why do they need to obtain the the server and command from the text?).

If you/they are going to 'fix' the error, then they will (should) be doing it at a point in the code where they already have that information at hand.

That is, if they are at a point where they could re-issue the command to a different server; or issue a different command to the same server; then they will be at a point where they have both available, because they provided that information to the call that cause the error (exception) in the first place.

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.

not very DRY). And if I ever decide to change that error message I have to then track down all the places that regular expression lives (which is much, much harder than searching for a simple string in piles of code) and change them.

The DRY solution is don't put copies of the same regex in multiple places. Define the regex once, name it, and import it wherever it is needed.

Yes they might have problems if I ever decide to restructure my exception hierarchy (which is much rarer than changing an error message) but even that can be handled by having some special isa() magic to make the new classes still look like the old to old code. Try doing that when you're just using strings.

You're fixing the symptoms, not the problem.

If the error applies to the same condition, it is the same error. The error handler shouldn't need to change because you changed the description of the error. And that is just as easily achieved using a regex as it is exception objects.


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^9: eval to replace die?
Download Code
Re^10: eval to replace die?
by phaylon (Curate) on Oct 05, 2010 at 13:21 UTC

    Chromatic suggested that using exceptions avoided "unreliable string comaprisons, substring comparisons and regexes". Which it doesn't. It just moves them.

    Yes it does. It's not the string comparisons and regular expression matches that are unreliable. It's the process of determining the type of an error by the representation of it (the message).

    For example, if you check if the error starts with "Foo", I will break your exception handling by throwing any error that starts with "Foo". That can't happen if the type of the error is carried externally to the representation shown to the user. And an object with a class is just that kind of an error. If you throw a MyError::Foo, I would have to explicitly throw that error or a subclass of it for it to be recognised by your error handling.

    Handling errors by message inspection works fine as long as you're the only developer in the code base. And never upgrade.


    Ordinary morality is for ordinary people. -- Aleister Crowley
      If you throw a MyError::Foo, I would have to explicitly throw that error

      And if I prefix my error messages with "MyError::Foo" you'd have to explicitly throw an error that started with that string to break my error handling.

      And if two modules chose bad namespaces--like MyError rather than MyModuleName::Error--then the same problem arises in code that uses both modules.

      The error vectors are exactly the same! It's still just string compare.

      The solution is in well chosen namespaces--whether error prefixes or execption class names.

      Just moving to throwing exception objects rather than strings does not fix the underlying problem: that of badly chosen namespaces!


      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.

        And if I prefix my error messages with "MyError::Foo" you'd have to explicitly throw an error that started with that string to break my error handling.

        Right, which can happen a lot, since I don't prefix my errors and often build error messages dynamically. So if my error is "MyError::Foo instance cannot be passed to do_something()", your error handling breaks. And it doesn't even do it consistently, it'll break depending on what I want to communicate to the user.

        Yes, bad namespaces are a problem. But there's no namespaces in error messages. It's all just a message. And while you can define for yourself that the start of the message is "the namespace," I'd rather use inheritance, since that has dedicated namespace functionality.

        Again, exception objects are for communicating with the rest of the program. Error messages are for communicating with the user. If you mix the two, there's worlds of pain down that road. Not to mention the fact that exception objects can carry optional stack traces and various other information, which makes them even more valuable to the user, even if it's just to communicate a better description of the error to a developer.

        If you really think $foo eq "bar" and $foo->isa('Something') are exactly the same, I'm quite concerned.


        Ordinary morality is for ordinary people. -- Aleister Crowley
Re^10: eval to replace die?
by mpeters (Chaplain) on Oct 06, 2010 at 19:45 UTC
    If you/they are going to 'fix' the error, then they will (should) be doing it at a point in the code where they already have that information at hand.

    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.

    If you think it's ok to just output an error message from a low level 3rd party module to the user of your software on the screen, then you've failed at creating usable software. If you don't use 3rd party modules (like CPAN modules) and all your users are programmers, and all of the users of your users (if you're writing modules that can be used by 3rd parties) are also programmers, then maybe you have an excuse.

    But I like the freedom to be able to decide how I want to handle different kinds of exceptions (escpecially if they have some kind of structured data) without having to resort to parsing every error message by hand. 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.


    -- More people are killed every year by pigs than by sharks, which shows you how good we are at evaluating risk. -- Bruce Schneier
      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.
        > 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)

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (10)
As of 2014-08-29 13:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (280 votes), past polls