http://www.perlmonks.org?node_id=494884


in reply to Re^3: Style guide for error messages?
in thread Style guide for error messages?

I think we disagree on what it means to do this badly.

First in what I do, the point of an exception is to cause a program to terminate, with a message made available (in a log, email, or on STDERR) that will give a programmer somewhere to start in fixing the problem. If that is the point, then creating an object is extra overhead that obscures what you're trying to do. Therefore for this specific scenario, creating an object is worse than just creating the message that you want to see logged. Because even though the effect may be the same, you obscured what was going on.

In the worst case, your error handler has a mistake and you don't successfully generate an object! Yes, we should all have tests. But reality is that our error checking code tends to be the least tested, and therefore should be coded in the most simple and straightforward way possible. It is harder to not notice messing up a string than a method call, so strings are to be preferred.

Now let's go on to the point that I initially made.

In general when I see exception objects being created, my expectation is that someone is intending to catch those objects and process them in interesting ways. Now sometimes that might be appropriate. For instance if you want to display messages in a language-localized fashion. Or if you need to display messages after postprocessing in various ways (text message for a command line, popup for a GUI, HTML for a web form). However it is not appropriate for what I'm doing. Which raises the question of why they are being used.

Now, as I said, I think that just constructing the final message is better because it is more straightforward. However what some people like to do is use exceptions as a general flow of control mechanism. Yes, I know that they have the capability of doing so - else they wouldn't be useful. But when people start using exceptions that way, you get into problems. Some people dislike that in all circumstances. I'm not entirely convinced of that, though I dislike the action at a distance. But the fragility of eval, $@ and die in Perl causes me to be particularly suspicious of the design idea because I know how easy it would be to just swallow exceptions rather than doing something useful with them.

And a random point on the topic. Re: Re2: Learning how to use the Error module by example mentions specific problems with one module that tries to make exception handling cleaner in Perl. I have no idea whether others are prone to the same kinds of issues, but unless I'm given some concrete benefits, it isn't worth my energy to find out.

Replies are listed 'Best First'.
Re^5: Style guide for error messages?
by rir (Vicar) on Sep 26, 2005 at 04:33 UTC
    Tilly, I don't think we disagree so much. I think we just think of differing situations. I was addressing xdg's concerns which seemed to indicate that string exceptions were getting messy.

    I apologize, you pretty much said all of TheDamian's arguments for exception objects are arguments for how to better use them for complex flow of control. I still think that statement is overly generalized and too prescriptive of intention, but perhaps TheDamian does argue for complex exceptional flow control. I do find some of his examples baroque. You may know Damian's intended meaning better than I. I apologize that my comments did not display any of the regard I have for the tilly you have shown here and that they reflected my ungenerous reading of your post. I guess you said "people" and I thought "Hey, I'm a people."

    But back to the issue.

    When you know the code that is going to handle, or not handle, your exceptions you are not in the situation in which exceptions shine. Exceptions are all about passing control to unknown code.

    The problem with object exceptions in Perl is that strings are the traditional default: So your expectation that something fancy is being done is reasonable. And that default makes it problematic for anyone writing a module for general use to use anything else. This will be slow to change until some exception package goes into the core. In the mean time, it is producers of larger applications who will be attracted to exception objects and those producers will be deterred by their relatively good info about what lies up the call chain, and by the need to deal with the string exceptions in modules they may use.

    The problem with string exceptions in Perl is that they are tedious and error prone to identify. Strings must be controlled by convention, Perl can help in this control if typed exceptions are used. Strings are brittle and unhelpful when you need to present your user with info that varies with some context far removed from the error. They just don't scale well. It only takes the need to discriminate a single exception from the many to start feeling this problem.

    If the optimisation (space?) is needed it is easier to factor exception objects into strings than the reverse.

    You and I could probably get by with printing a message and exiting instead of dieing. This would also make explicit that handling was not intended. Using an exception in this degenerate case promotes reusability by being flexible, using object exceptions extends this flexibility. Not using this flexibility is not misleading to me.

    Be well,
    rir

    #! /usr/bin/perl use warnings; use strict; package X; use Carp; use overload ( qq{""} => sub { return $_[0]->{description}; } ); sub new { my ( $class, $description ) = @_; $description = "Exception of type $class occurred" unless $descrip +tion; #no strict "refs"; #dprint "mutts under class" if ( 1 < @{"$class\::ISA"} ); #dprint "directly instantiated" if $class eq __PACKAGE__; bless { description => $description . Carp::longmess() }, $class; } sub caught { my $class = shift; return $class if ( $class eq ref $@ ); return; } package Eperm; use base "X"; package main; sub fail { die Eperm->new() } fail();
    ~
      I'll respond selectively.

      I apologize, you pretty much said all of TheDamian's arguments for exception objects are arguments for how to better use them for complex flow of control. I still think that statement is overly generalized and too prescriptive of intention, but perhaps TheDamian does argue for complex exceptional flow control...

      By my reading of PBP, the cited benefits of objects over strings have to do with how easy it is to postprocess exceptions in code. His rules on the topic have to do with the advantages for handlers that are trapping exceptions, the best ways to write those handlers and the best way to structure exception class hierarchies. Those are all appropriate to how to use exceptions for complex flow of control. Oh, he also suggests that exceptions should be thrown on all failures, including recoverable ones, which should then be trapped. (The latter choice affects the other choices he makes. Many of his best practices hang together like this - which is why it is a bad idea to pick and choose individual suggestions without a good understanding of why they are made.)

      My understanding of those rules and what he wrote is indeed as a series of arguments for how to better use them for complex flow of control. Specifically for flow of control where you are throwing exceptions, catching them in handlers, and the handlers are then making complex decisions on what to do with the exceptions.

      When you know the code that is going to handle, or not handle, your exceptions you are not in the situation in which exceptions shine. Exceptions are all about passing control to unknown code.

      Yes, that is what they do. That is not what they're for though.

      The point of exceptions is to provide a standard way to handle exceptional events without having to litter your code with gotos or checks of returns. Those are the common alternatives in languages without exceptions. Exceptions are better than checking return because it is less error prone. They are better than goto because they lend themselves to clear mental models of what will happen in a particularly important set of circumstances. My preference is to settle on a style that makes that clear mental model as clear and simple as possible.

      The problem with string exceptions in Perl is that they are tedious and error prone to identify. Strings must be controlled by convention, Perl can help in this control if typed exceptions are used. Strings are brittle and unhelpful when you need to present your user with info that varies with some context far removed from the error. They just don't scale well. It only takes the need to discriminate a single exception from the many to start feeling this problem.

      Let's compare problems. If you use object based exceptions, one problem is that typos will mean that at the point where you're hoping to capture that critical piece of information about an error you'll instead find out that, due to a typo, you lost your information. That seems to me to be a tragedy. You complain about how hard it is to identify strings. By contrast I want a unique enough error message that I can find where it is generated by using grep. Furthermore I'd like strings to be descriptive enough that they document what went wrong. You complain about how to present the information in the exception to users. I'd prefer to be uninformative to users, but detailed to developers. YMMV but I've not had problems with the scalability of exceptions in projects with 100K lines of code. And if it comes to wanting to discriminate one exception, my first question is why you want to do that (sample good reason that I've needd, for an alarm timeout), and my second approach is that it is trivial to include a unique string in the exception. (The first approach that comes to mind is to write a brief explanation in the error, then grep for that explanation. But one could also include a random string.)

      You and I could probably get by with printing a message and exiting instead of dieing. This would also make explicit that handling was not intended...

      You could, I could not.

      I want my file and line number captured. This is far more important to me than adhering to someone else's notion of good style.

      (Code snipped.)

      I hope you didn't think this code sample was going to change my mind?

      Looking at it, what I see is a bunch of code to do the same thing that calling confess does, but less reliably. Oh, it also starts the stack from an internal function call for no real reason. You're being encouraged to separate messages from the place where they are generated, making you less likely to produce a useful message (you know, one with $!, arguments, a statement of what you were trying to do..). The default message is uninformative And your fail() function won't accept an argument, so you're guaranteed to get the default message. Plus, as I mentioned before, if you have a bunch of these, a typo on a class name when you call the exception can leave you with a hidden landmine - you think you're going to get a useful message when you're not! (Of course I could also have a typo typing confess(), but since that is just one word and my fingers are very used to typing it, I'm unlikely to mess that up. I'm far more likely to mess up class names.)

      To recap, here is a summary of my position.

      For the simple case, objects are worse than strings. If you want to be more complex, then objects are an obvious win. I'd prefer to KISS, and would like to discourage complexity. (Admittedly, there are applications where that complexity is needed, but I'm not dealing with any.)

        You mentioned gotos and returns. On this list should be the closer cousin: semaphore flags. Flags are worse than exceptions because they are advisory.

        I want my file and line number captured.

        That goes into the message.

        I was not complaining nor was I trying to change your mind (or practices); even brilliant men can disagree.

        I'd prefer to be uninformative to users, but detailed to developers.

        With objects one can inform both appropriately.

        if it comes to wanting to discriminate one exception, my first question is why you want to do that

        An example: A fair sized body of code, being 7 or more calls deep, explores the environment of the program. The scope of the environment is expanded and now failure to access a few resources is no longer reason to exit, instead by expressing the problem at the new top level, a separate tree of code is able to substitute some of the new resources instead. So now we want to discriminate a few exceptions from the many. Capturing some data to present to the user may also be appropriate.

        That your fingers are trained to type confess is a valid and compelling reason to practice as you do, but it gave me a laugh. I thought of some programmer trying to use that as a justification to his boss--what made that image really funny is that such idiocynratic issues can have a serious impact on productivity.

        For the simple case, objects are worse than strings. If ... more complex, then objects are an obvious win.

        I agree with your opinion as you summarize it.

        Be well,
        rir