Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

How are exception messages commonly stored? for any domain. I'm thinking about this from a maintenance standpoint.

if(!Condition1)
    throw new Exception("Some exception");

if(!Condition2)
    throw new Exception("Some exception");

If it was decided that the exception message in that snippet needed to be changed, it would have to be changed in two places; leaving it wide open for inconsistent messages and such.

How better to store exception messages then? Perhaps as a static class with constants?

public static Exceptions
{
    public const string CONDITION_NOT_MET = "Some exception";
}
...
if(!Condition1)
    throw new Exception(Exceptions.CONDITION_NOT_MET);

if(!Condition2)
    throw new Exception(Exceptions.CONDITION_NOT_MET);

Are they often (in production) hardcoded?

share|improve this question
    
Are you really throwing generic "Exception" instances? That's a terribly bad practice. –  S.Lott Jan 4 '12 at 11:49
    
It's just an example –  AndyBursh Jan 4 '12 at 11:59
3  
To make that clear, it's customary to use something like MyUniqueException or ApplicationException or something that's clearly not the built-in superclass. –  S.Lott Jan 4 '12 at 12:20

3 Answers 3

up vote 8 down vote accepted

I will chime in with what @MikeNakis says: the exception type used should be fine-grained enough that you can discern to some reasonable degree what the problem was from looking only at that and possibly the stack trace. If the intent was that one should just throw Exceptions around, then that type would have been made final, sealed or whatever happens to be the term in one's programming language of choice, but that is not the case in any language or framework I know of. In fact, catching Exception is often frowned upon, as it is a cop-out that is very likely to hide real, serious problems.

The exception message should be used to provide details that cannot reasonably be expressed through the type system.

Your second example is actually worse, IMO: you are replacing hard-and-fast types with string literals that are bound to become out of date, misused, changed in ways not expected in some parts of the code, or in any number of other possible ways inaccurate. And in ways that the compiler doesn't have a glimmer of hope of helping you catch, in any language.

Exception messages should not need to be changed. To the extent that they are to be used at all (which should be sparingly, IMO; see previous discussion), they should be meant for programmers (and possibly power users, who can enable display of the messages through some mechanism), not end users. Thus, the exact phrasing becomes less important than the fact that the message clearly describes the conditions that caused the exception but which cannot be adequately expressed through the type system.

Also, unless you really need free-form text messages with no built-in semantics as exception clarifiers (unlikely), you are almost always better off forgetting entirely about building and passing a single string message. Let's say you have a piece of code that requires that a certain variable is within a given range, and must throw an exception otherwise. Instead of (pseudo-C#/.NET; I know you could use string building features like StringBuilder or String.Format, but that's not the point here):

if (x < 3 || x > 10)
    throw new VeryGeneralException("Got " + x.ToString() + " wanted min 3 max 10");

you might do something like:

public class OutOfRangeException : Exception
{
    public int Value { get; private set; }
    public int MinValue { get; private set; }
    public int MaxValue { get; private set; }

    public OutOfRangeException(int value, int minvalue, int maxvalue)
    {
        base("Got " + value.ToString() +
             " wanted min " + minvalue.ToString() + " max " + maxvalue.ToString());
        this.Value = value;
        this.MinValue = minvalue;
        this.MaxValue = maxvalue;
    }
}
... then far later ...
if (x < 3 || x > 10)
    throw new OutOfRangeException(value: x, minvalue: 3, maxvalue: 10);

That way:

  • by looking at only the exception type name, you know that some value was out of its allowed range
  • with the resulting generated message, you know the value of the variable in question and its expected range
  • along with the full stack trace, you have a pretty decent idea how you got to that point (which, depending on the architecture and the semantics of the value in question, may or may not help you determine why the value was out of its allowed range)

This way, a single exception, including its stack trace, gives you about as much detail as you can hope to get short of a step-by-step description of how to repeat the error.

share|improve this answer
    
+1, well said. I updated my answer too, before I saw yours, and I am basically saying the same thing. –  Mike Nakis Jan 4 '12 at 12:25
    
You still need to dig out the source code to see exactly what went wrong. Please see my answer for a suggestion on how to include the failed condition in the stacktrace. –  user1249 Jan 4 '12 at 12:51
    
@ThorbjørnRavnAndersen, please see my edit at the end. :) –  Michael Kjörling Jan 4 '12 at 12:53
    
"I know of. In fact, catching Exception is often frowned upon, as it is a cop-out that is very likely to hide real, serious problems." - The practice that is frowned on is catching and ignoring exceptions. –  Stephen C Jan 5 '12 at 4:33
    
@StephenC How are you going to sensibly handle a top-level Exception in an exception handler (note that I did not write "catching exceptions") in the general case? Nearly every catch(Exception) block I've seen in practice could have been either avoided entirely, or rewritten to catch an appropriate subclass of Exception. Also note that the statement was written in the context of responding to throwing Exception and using the exception message to convey information about the nature of the error. –  Michael Kjörling Jan 5 '12 at 9:02

In my opinion the constructor of Exception should not be accepting a string message parameter, nor any other kind of identifier that stands for the message. The message is the name of the type of the exception.

In my projects for convenience I make use of an exception that I call GenericException which accepts a string message, but the intent is to replace it with a specific exception type, created especially for that purpose, before deployment, ideally before source code commit.

What you can do is have a dictionary in which the key is an exception type and the value is the corresponding message. You can also use formatting in the message, and use reflection to fetch values of members of the exception, and pass them to the String.Format function, so as to make your messages richer.

So, in your case you should define a ConditionNotMetException, derived from System.Exception. If you have no other information to pass in it, then leave it as an empty class. Alternatively, you may want to include some members in it, containing additional information about the condition which was not met, why it was not met, etc.

However, these members should be just raw values, they should not be processed into string messages by the exception. For example, if you had an exception called DateOutOfRangeException you may want to include in it 3 DateTime fields: one for the date that was found to be out of range, and another two defining the range. Then, it is the responsibility of the application to present the user with a meaningful message containing these three dates.

share|improve this answer

Let the message be telling. A good thing to tell is what went wrong:

if(!Condition1) throw new Exception("!Condition1");

if(!Condition2) throw new Exception("!Condition2");

The more complex the expression in the if the more information you will need to avoid a debug step. For instance

if ((x>10) || (y<0)) throw new RuntimeException("(x>10) || (y<0), x="+x+",y="+y);

This will allow the maintenance engineer to analyze the error without having to run the program again. Some day you will appreciate this

share|improve this answer
    
I know it is only an example, but I would probably split that "more complex" if statement into two, one checking x and one checking y. Of course in some situations it may not be possible (that all depends on the exact conditions involved), but where it is, I find that the increased clarity (particularly when the exception gets thrown) tends to outweigh the very slight increase in the amount of code. –  Michael Kjörling Jan 4 '12 at 12:41
    
No problem in splitting, as long as the value of x is included in the message if the condition tested x. –  user1249 Jan 4 '12 at 12:45
    
Absolutely, the condition that caused the exception to be thrown should be adequately described by the exception message (see my answer). I just personally don't very much care for conditionals with several completely separate conditions leading into the same if statement-block, particularly when that statement-block needs to be specifically written to cater to all of those conditions when they can easily be split up. –  Michael Kjörling Jan 4 '12 at 12:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.