Live data from Hacker News

Code Design Decision – Always throw custom exceptions

github.com

41–50 of 92 posts

Re: Code Design Decision – Always throw custom exceptions

#41
post #13
post #8

Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case . YAGNI. 1. You don't know which exceptions will be raised in advance. Anything that involves IO can fail in a plethora of ways, and you don't even know which calls involve IO (e.g. a library might choose to cache something on disk). 2. Consumers of your code will not know how to deal with those excep…

I think there are two kinds of exceptions in languages that have them as their error handling mechanism. 1. Exceptions you expect your consumers to handle. 2. Exceptions you don't expect your consumers to handle. The first one I would argue you should wrap third party exceptions. There is in nearly every case important context in your code that the thrower of the third party exception will not know and whoever is rea…

I'm reminded of an old Eric Lippert post about this. He basically says the same as you: boneheaded and fatal exceptions are not meant to be caught, and vexing and exogenous exceptions are ordinary flow control.

https://ericlippert.com/2008/09/10/vexing-exceptions/

Re: Code Design Decision – Always throw custom exceptions

#42

This idea can also be explored in the Go programming language. Go has an error type, not exceptions, but error checking famously can be rather verbose. Two cases to consider come to mind. First, the common pattern result, err := SomeFunc() if err != nil { return err } Here the code is just passing along the error to the caller, unchanged. Second, signaling errors ab initio result := // some calculation or behavior if…

The whole DomainError thing only makes sense if you expect someone to handle this error (and by handle, I mean doing something other than logging and aborting some operation), or if you are writing a very generic library. Otherwise, it is wasted time and extra complexity that makes the code harder to read.

Yes, that's true, just as it is with exceptions in the original article. However, if you are writing the code and it's callers, if you don't want to handle the error, why even have it? Just log the results there and move on.

Re: Code Design Decision – Always throw custom exceptions

#43
post #39

Earlier quoted context omitted.

Typed exceptions convey a bit of information to enable specialized handling at runtime, they are not meant to try and make debugging easier.

I'm not sure what you mean by "they're not meant to". They work, I don't care what they're "meant to" do. It also helps with general analysis of logs.

It's redundant.

The message (a string) will give you that information, nothing is lost by catching a base Exception and writing it to a log.

typed exceptions is about special handling. The type information allows the programming language to offer special handling when that is necessary, it is NOT meant to replace good error messages.

But it also isn't about taxonomy, which is something that a lot of people miss. It's putting the cart before the horse.

---

But you specifically talked about debugging. If you're talking about interacting with an attached debugger, the developer already has everything they need, there is no reason why specific, typed, exceptions are needed to assist that.

so you MUST be talking about general debugging by reading logs and the like, but those logs will tell you both the error message and the stack trace with the specific line that originally threw. Unless, of course, you're catching and rewrapping the exception and throwing that information away...

Re: Code Design Decision – Always throw custom exceptions

#44
post #13

Earlier quoted context omitted.

I think there are two kinds of exceptions in languages that have them as their error handling mechanism. 1. Exceptions you expect your consumers to handle. 2. Exceptions you don't expect your consumers to handle. The first one I would argue you should wrap third party exceptions. There is in nearly every case important context in your code that the thrower of the third party exception will not know and whoever is rea…

This is one of the problems with checked exceptions. The library author is in no position to expect me to handle an exception. Whether or not I can relies on the design of my system, which they have no window into.

If it's an unchecked exception experience says I have a 60-70 percent chance of not knowing it's there without a careful reading of the code. Which means I can't know myself if it's possible to handle it or not. I can always rethrow an exception if I know it exists. Languages that give me a way to ensure I know about it means I avoid unnecessary pain later in production with someone breathing down my neck to please fix it now. I'll take that any day over a little boilerplate.

Re: Code Design Decision – Always throw custom exceptions

#45
This is a reasonable approach, but having a catch-all case that handles the exception and re-throws it, but wrapped in custom exception type can be problematic in case a new exception is added - the consumer of the API needs to go over their code and change the types everywhere, or else their catch code will not be working as before anymore.

This problem can easily go unnoticed, judging by my Haskell experience.

The solution would be to always use "checked exceptions" (or similar concept in your language, e.g. `ExceptT SomeEnumType` in Haskell) and never use catch-all cases (or wildcard patterns, in case of Haskell), so that every exception handling case is tagged with exception type, and type-checked.

Re: Code Design Decision – Always throw custom exceptions

#46

Like others have said, in theory this is great. In reality, I never see custom exceptions being handled differently than whatever exception was wrapped. And I have worked on some large distributed systems where failure is common. For new engineers these custom exceptions add abstract complexity and exception class hierarchy into a code base when it really isn’t needed.

I disagree. I have seen plenty of code that is forced to match on the text of an exception because it uses a too-generic type. That said, I still wouldn't use a custom exception type in most languages simply because it's so tedious for a small pay-off. It's one of those things that you should do, but isn't really worth the hassle. Like putting alt text on HTML images. Do any languages with exceptions let you define n…

I don't see how an exception type defined at the throw site would be significantly different than using the text of the exception to convey the type. Callers wouldn't know to expect it either way, so how would they be able to handle it effectively?

Re: Code Design Decision – Always throw custom exceptions

#47
post #13
post #8

Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case . YAGNI. 1. You don't know which exceptions will be raised in advance. Anything that involves IO can fail in a plethora of ways, and you don't even know which calls involve IO (e.g. a library might choose to cache something on disk). 2. Consumers of your code will not know how to deal with those excep…

I think there are two kinds of exceptions in languages that have them as their error handling mechanism. 1. Exceptions you expect your consumers to handle. 2. Exceptions you don't expect your consumers to handle. The first one I would argue you should wrap third party exceptions. There is in nearly every case important context in your code that the thrower of the third party exception will not know and whoever is rea…

"Exceptions you expect the consumer to handle" should be explicit return values on the function signature instead, via an Either/Result type or similar.

Unless you're writing Java where you can force certain exception types to be handled, but people never write that code properly.

Re: Code Design Decision – Always throw custom exceptions

#48
post #8

Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case . YAGNI. 1. You don't know which exceptions will be raised in advance. Anything that involves IO can fail in a plethora of ways, and you don't even know which calls involve IO (e.g. a library might choose to cache something on disk). 2. Consumers of your code will not know how to deal with those excep…

> Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case. YAGNI. I'm going to curse here, but ... fucking seriously. If I get a .net ADO exception coming out of a 3rd party library it's absolutely not going to shock me or throw me for a loop. But do you know what IS a pain in the ass? Using 3 different libraries, all that wrap that same ADO exception in t…

Haha, that's actually a good point. A single problem can affect dozens of modules, each having a different wrapper.

If my db goes down, I very much prefer to see a single DatabaseConnectionFailed than a multitude of FailedToSaveObject, DatabaseError, CannotLoadData, IOError, SomethingIsWrongThisShouldNeverHappen, DBHostUnavailable all over the place. Good luck navigating through the noise and isolating those.

Re: Code Design Decision – Always throw custom exceptions

#49
post #8

Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case . YAGNI. 1. You don't know which exceptions will be raised in advance. Anything that involves IO can fail in a plethora of ways, and you don't even know which calls involve IO (e.g. a library might choose to cache something on disk). 2. Consumers of your code will not know how to deal with those excep…

> Just because it's useful to wrap exceptions in 5% of the cases doesn't mean you should wrap the rest 95% just in case. YAGNI. I'm going to curse here, but ... fucking seriously. If I get a .net ADO exception coming out of a 3rd party library it's absolutely not going to shock me or throw me for a loop. But do you know what IS a pain in the ass? Using 3 different libraries, all that wrap that same ADO exception in t…

What do you use libraries for if not for the abstraction layer?

Re: Code Design Decision – Always throw custom exceptions

#50
post #21

Earlier quoted context omitted.

This is one of the problems with checked exceptions. The library author is in no position to expect me to handle an exception. Whether or not I can relies on the design of my system, which they have no window into.

That is true, so the library should throw the checked exception, and if the caller has no way to handle it, it should wrap the checked exception in an unchecked exception and throw the unchecked exception. Not too hard, and library clients that can handle some checked exceptions will be able to. I hate libraries that only throw unchecked exceptions. It seems easier initially, but makes writing correct code more diffi…

> If the caller has no way to handle it, it should wrap the checked exception in an unchecked exception and throw the unchecked exception.

Not you have a new problem: How is the code calling the caller supposed to know about that exception? You can't even catch it (even if you know about it!) using normal try-catch because what you have to do is catch the wrapper exception and then check inside that for the exception type you expect via instanceof.

Checked exceptions (at least as implemented in Java) are horrible for the composability of code wrt. error handling.

That is why most libraries eschew checked exceptions these days. Unfortunately, large bits of the standard library in Java forces their hand wrt. re-wrapping stuff like InterruptedException and IOException and the like.

(Not to mention, most of the time you really shouldn't be catching exceptions in very small scopes or at the very highest level in your code. Involving every single layer in between is madness.)

Post reply on HN