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.

Suppose there are some methods to convert from "X" to "Y" and vice versa; the conversion may fail in some cases, and exceptions are used to signal conversion errors in those cases.

Which would be the best option for defining exception classes in this context?

  1. A single XYConversionException class, with an attribute (e.g. an enum) specifying the direction of the conversion (e.g. ConversionFromXToY, ConversionFromYToX).
  2. A XYConversionException class, with two derived classes ConversionFromXToYException and ConversionFromYToXException.
  3. ConversionFromXToYException and ConversionFromYToXException classes without a common base class.
share|improve this question
    
Are these conversions simple? More specifically: is a large amount of composite data types being batch-converted? In the latter case, the result might be partly successful and partly failed. Non-fatal conversion warnings might be needed for issues that are not critical enough to warrant throwing an exception. –  rwong Oct 31 '12 at 11:37
    
@rwong: The conversions are all-or-nothing: either they succeed or they fail. In case of failures, exceptions are thrown. –  Mr.C64 Oct 31 '12 at 11:57

3 Answers 3

up vote 8 down vote accepted

The foremost reason for having different exception types is to be able to catch them selectively.

So the question you should ask yourself is: Will you ever have a piece of code where conversion might fail and you only want to catch conversion errors in one direction and not the other? If so, having two distinct exception classes is the best way to go. If you want to be able to catch both in the same clause, then you need a common super class as well.

If you do find it hard to anticipate how the exceptions are caught, then stick to YAGNI and go with the first option. You can always add the subclasses later if you ever actually need them.


Apart from that, I think you should ask yourself whether exceptions are the right way to signal conversion failure, because in fact failure is an expected option. In fact a lot of APIs merely use sentinel values for that.

Another nice way to propagate errors would be to wrap return information of any call that can fail like this (in pseudo-code):

 class Outcome<Result, Error> {
      const Bool success;
      const Result result;
      const Error error;
      Result sure() {
           if (success) return result;
           else throw error;
      }
 }

 Outcome<X, { value: Y, message: String }> convertYToX(Y y) {
     if (suitable(y)) return Outcome{ success: true, result: convert(y) };
     else return Outcome{ success: false, error: { }};
 }

And then either do:

 handleX(convertXToY(myY).sure());//will throw an exception if an error occurred

Or inspect the result yourself:

 var o = convertXToY(myY);
 if (o.success)
     handleX(o.result);
 else {
     log('error occured during conversion:');
     log(o.error.message);
     log('using default');
     handleX(defaultX);
 }
share|improve this answer
    
+1 For not throwing exceptions for expected behavior. –  Songo Oct 31 '12 at 16:10

Don't over-think it,

My suggestions:

Regarding the signature of the constructor, all over the Java API, classes that extend Exception, uses one or more of the following constructors:

1. PrintException()  // Construct a print exception with no detail message.
2. PrintException(Exception e) // Construct a print exception chaining the supplied exception.
3. PrintException(String s) // Construct a print exception with the given detail message.
4. PrintException(String s, Exception e) // Construct a print exception with the given detail message and chained exception.

I really think that one or two of this constructors will suffice for you, probably 1 and 3.

Regarding whether or not you should have separate exceptions for X->Y and Y->X, I strongly advice not to do so, because you will end up writing exceptions for Z->X, X->Z, P->Q, Q->P, Q->X, Q->Y and a lot of permutations. You shoul ask what is the added value of this.

share|improve this answer
    
This should either be a comment or you should actually provide at least some sort of reasoning. –  back2dos Oct 31 '12 at 12:51
    
@back2dos You are right, I improved my answer. –  user61852 Oct 31 '12 at 14:42

What language? Many languages already have well defined Exception classes. You would just derive from those and add the details.

For something trivial like this, a single ConversionException should be enough, details can go into the class.

As a Ruby programmer I would even consider to just use the default exception class and put the details into the message part it provides under some circumstances.

share|improve this answer
    
This was C++ related, but I think that's not very important to the question. I think the question is pretty language-agnostic. It's not interesting to know if the exception class is derived from std::runtime_error or CAtlException or something different; the focus is on how to organize the custom exception class(es). –  Mr.C64 Oct 31 '12 at 11:59

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.