Should my custom exception types be case class
es?
On the plus side, I get extractors.
On the minus side, I get incorrect equality semantics. But I can avoid that by overriding equals
.
So does it make sense, at a conceptual level, to make them case class
es?
You add a new exception class when a user of your API might need to catch it conditionally (or, for checked exceptions specify different, specific types in a throws ).
If both base and derived classes are caught as exceptions, then the catch block of the derived class must appear before the base class.
The answer is simple: Case Class can extend another Class, trait or Abstract Class. Create an abstract class which encapsulates the common behavior used by all the classes inheriting the abstract class.
The JVM is responsible for finding an exception handler to process the Exception object. It searches backward through the call stack until it finds a matching exception handler for that particular class of Exception object (in Java term, it is called " catch " the Exception ).
This is very subjective of course, but in my opinion it is good practice to have exception classes as case classes. The main rationale being that when you catch an exception, you are doing pattern matching, and case classes are much nicer to use in pattern matching. Here's an example that takes advantage of the ability to use the full power of pattern matching in a catch block, when using a case class exception:
object IOErrorType extends Enumeration { val FileNotFound, DeviceError, LockedFile = Value } case class IOError(message: String, errorType: IOErrorType.Value) extends Exception(message) def doSomeIO() { throw IOError("Oops, file not found!", IOErrorType.FileNotFound) } try { doSomeIO() } catch { case IOError( msg, IOErrorType.FileNotFound ) => println("File not found, please check the path! (" + msg + ")") }
In this example, we have only one exception, but it contains an errorType
field for when you want to know the exact error type that occurred (usually this is modelled through a hierarchy of exception, I'm not saying this is better or worse, the example is just illustrative). Because the IOError
is a case class I can simply do case IOError( msg, IOErrorType.FileNotFound )
to catch the exception only for the error type IOErrorType.FileNotFound
. Without the extractors that we get for free with case classes, I would have to catch the exception everytime, and then rethrow in case I'm actually not interested, which is definitely more verbose.
You say that case classes give you incorrect equality semantics. I don't think so. You, as the writer of the exception class gets to decides what equality semantics makes sense. After all when you catch an exception, the catch block is where you decide which exceptions to catch usually based on the type alone, but could be based on the value of its fields or whatever, as in my example. The point is that the equality semantics of the exception class has little to do with that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With