5

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.
asked Oct 31, 2012 at 11:05
2
  • 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. Commented Oct 31, 2012 at 11:37
  • @rwong: The conversions are all-or-nothing: either they succeed or they fail. In case of failures, exceptions are thrown. Commented Oct 31, 2012 at 11:57

3 Answers 3

9

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);
 }
answered Oct 31, 2012 at 11:43
1
  • +1 For not throwing exceptions for expected behavior. Commented Oct 31, 2012 at 16:10
1

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.

answered Oct 31, 2012 at 12:35
2
  • This should either be a comment or you should actually provide at least some sort of reasoning. Commented Oct 31, 2012 at 12:51
  • @back2dos You are right, I improved my answer. Commented Oct 31, 2012 at 14:42
0

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.

answered Oct 31, 2012 at 11:18
1
  • 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). Commented Oct 31, 2012 at 11:59

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.