Live data from Hacker News

You’re better off using Exceptions

eiriktsarpalis.wordpress.com

61–70 of 242 posts

Re: You’re better off using Exceptions

#61
post #19
post #4

When I moved to Rust the constant error wrapping or converting annoyed me. But after using it for a couple of years it turned out to be a huge blessing. Quite often I need to know exactly which error messages will be thrown so that I can do things like internationalization. While exceptions are quite convenient for prototyping for production I’m now firmly in the typed errors camp.

I don't know Rust at all but what you're talking about sounds equivalent to (much maligned) Java's checked exceptions system? I never understood the hatred checked exceptions received especially from the younger crowd. I still write Java at work and I still use checked exceptions whenever they indicate an error condition that must not be ignored by the client code. Many new to the project developers hate me for it in…

> I never understood the hatred checked exceptions received especially from the younger crowd.

I worked with Java professionally for several years and in a sense I feel the same: Checked exceptions are not as bad as they are often portrayed.

At the same time they are certainly not as nice as text book examples make them seem to be. For me the biggest downside always has been that their types are part of the method signature and therefore whenever you change the exception type of one class you more often than not end up refactoring half of your other classes too.

Re: You’re better off using Exceptions

#62

My problem with exceptions isn't so much exceptions themselves but the way they're used. The way I see it, exceptions should only be used for things that are irreconcilable, which most of the time is interpreter errors(e.g. undefined is not a function). In other words, I don't think it's that common that custom exceptions are needed outside of assertions to prevent the developer from doing something stupid. If you ar…

> A record not being found is a normal thing!

It's not a normal thing for code that needs that record that wasn't found.

> They literally tell you nothing and there's no way to solve them without catching/rescuing them. A null value, a plain "error" object, or an error argument in a callback would have been sufficient. If I need an exception to be raised for this kind of thing, I'll do it myself.

They tell you lots: you asked for something your code path wanted and your request couldn't be satisfied. Also, you've been helpfully kicked onto the alternative execution path to handle that situation.

Exceptions are a hell of a lot better than littering your code with null checks or error code checks, especially when you forget one and get a null pointer error or your code wanders away from the root cause and fails later.

Re: You’re better off using Exceptions

#63
post #19
post #4

When I moved to Rust the constant error wrapping or converting annoyed me. But after using it for a couple of years it turned out to be a huge blessing. Quite often I need to know exactly which error messages will be thrown so that I can do things like internationalization. While exceptions are quite convenient for prototyping for production I’m now firmly in the typed errors camp.

I don't know Rust at all but what you're talking about sounds equivalent to (much maligned) Java's checked exceptions system? I never understood the hatred checked exceptions received especially from the younger crowd. I still write Java at work and I still use checked exceptions whenever they indicate an error condition that must not be ignored by the client code. Many new to the project developers hate me for it in…

The failure mode of a module is a function of its implementation. Beyond simple argument and state validation, interesting failure modes are usually abstraction violations.

The tension between needing to communicate the actual reason for a failure (which violates abstraction) and preserving the abstraction (which demands shoehorning error states into some kind of polymorphic receptacle) is at the heart of the problem with checked exceptions.

If you try and pass through the failure mode, then new implementations cause new failure modes, which means methods grow new exceptions, which in turn break downstream dependencies, because adding a new exception to the throws clause is a breaking change.

If you try and abstract away the differences in failure mode (e.g. with a specific module exception), then you fill the code with boilerplate wrappers, need to translate exceptions at module boundaries, and (in the worst case) invent taxonomies into which all future implementations must awkwardly categorize their failure modes.

Specific to Java, there's another bug. The type system can express sum types only for concrete exceptions and not for generics. That means that if you parameterize code with other code (e.g. with a lambda or callback), the argument code can only throw pre-defined or runtime exceptions; there's no way to declare, in the type system, the transitive set of exceptions across control flow when the set of exceptions is determined by the argument. E.g. if you have a generic map(f) method, you can't generically declare that map() throws whatever f() throws without forcing f() to only throw a single checked exception - generic type arguments can't be the sum types that Java permits in throws and catch clauses.

All this is costly. Meanwhile, in most actual applications, exception handling is extremely rare; exceptions are almost always propagated up to a top-level handler and logged. When exceptions are handled, it's usually near the leaves of the control flow graph, where the application interacts with other systems, like the network or the file system; these inherently non-deterministic failures often need explicit management. So the work to propagate the exception types throughout the control flow graph is pointless.

Re: You’re better off using Exceptions

#64
> ...exceptions-as-control-flow abuse or even the assertion that exceptions are really just a type safe version of goto.

I was recently telling someone about a little-known Java feature that I wish C would adopt. Goto is common in C exception handling code because the alternative is unworkably messy. Java has named code blocks that you can break out of, so they're not gogo, but they're also not exception abuse.

    initBlock: {
      if (fail) { break initBlock; }
      doSomething();
    }

Re: You’re better off using Exceptions

#65
post #24

Earlier quoted context omitted.

Maybe I am missing something but I think every dynamic typing system has this problem. I can't see what this has to do with Python and exceptions in general. It is not like there aren't statically typed languages with exceptions. This comment is an excellent critique of dynamic typed systems but it has nothing to do with exceptions.

The top-thread post was referencing Python, so I'm speaking in the Python domain specifically. Other dynamic languages have this problem also, and other languages with stronger static type guarantees do support exceptions. I haven't encountered a language with dynamic typing of the sort Python has that doesn't also have a robust runtime exception system, and it'd be interesting to see what that looks like. There's pr…

I guess I was too fixated on the exceptions part of your comment. You are right that due to Python's dynamic nature every line can turn into a runtime exception. Maybe it's because English is my second language but I couldn't understand that in your first comment.

Re: You’re better off using Exceptions

#66

My problem with exceptions isn't so much exceptions themselves but the way they're used. The way I see it, exceptions should only be used for things that are irreconcilable, which most of the time is interpreter errors(e.g. undefined is not a function). In other words, I don't think it's that common that custom exceptions are needed outside of assertions to prevent the developer from doing something stupid. If you ar…

Your example is a good argument for using null or empty list in situations where that is applicable, but it doesn't explain why a custom error object or callback would be better than using an exception, even in reconcilable scenarios. In fact I think using a custom error object would go against your general point of taking advantage of preexisting language features where possible.

Re: You’re better off using Exceptions

#67

My problem with exceptions isn't so much exceptions themselves but the way they're used. The way I see it, exceptions should only be used for things that are irreconcilable, which most of the time is interpreter errors(e.g. undefined is not a function). In other words, I don't think it's that common that custom exceptions are needed outside of assertions to prevent the developer from doing something stupid. If you ar…

If you expected the record to be found, the failure of finding it is an exception. If it was an open question, then it isn’t. This is why API generally have checks that allow developers to avoid that failure if the failure is expected (eg Record.exists). What you are suggesting is simply a reverse order (check after vs check before). I think check before leads to a much cleaner API than one that dumps a null or failu…

> If you expected the record to be found, the failure of finding it is an exception.

This is not always the case. In fact, for query APIs I do not expect it at all. Sometimes I'm doing something similar to a UPSERT operation with more nuanced behavior, then returning no existing entry on a preceding SELECT query could be the 99% use case.

Re: You’re better off using Exceptions

#68

My problem with exceptions isn't so much exceptions themselves but the way they're used. The way I see it, exceptions should only be used for things that are irreconcilable, which most of the time is interpreter errors(e.g. undefined is not a function). In other words, I don't think it's that common that custom exceptions are needed outside of assertions to prevent the developer from doing something stupid. If you ar…

Actually, I think exceptions are the clearest way to represent errors of any kind (reconcilable or not). > A null value, a plain "error" object, or an error argument In my mind, this just adds a lot more mental overhead while also being less informative than a simple exception. Plus you have to keep track of which method your current library has chosen to represent errors. Note I am biased from using Python for a lon…

For me exceptions are for exceptional cases.

Any time you have user input, you can expect errors and so should have proper paths to handle file not found, invalid input, ... For those case, exceptions should not be used.

Re: You’re better off using Exceptions

#69

My problem with exceptions isn't so much exceptions themselves but the way they're used. The way I see it, exceptions should only be used for things that are irreconcilable, which most of the time is interpreter errors(e.g. undefined is not a function). In other words, I don't think it's that common that custom exceptions are needed outside of assertions to prevent the developer from doing something stupid. If you ar…

Absolutely. Whether a method throws or not signals the intent of the code. In .NET, there are plenty of throwing and non-throwing versions of various methods. For example, there are both Parse() and TryParse() and also First() and FirstOrDefault() in Linq. Which method you use signals to the reader the expected result. If you're using Parse() then you're expecting the parse to succeed; Perhaps the data comes from a d…

On the other hand, if you are writing library code or even a library-ish component of application code, having to write the same method a bunch of different times is tedious. Ideally, the language would be designed so that there is one sane way of propagating errors, which can be easily either handled or propogated.

I am quite a fan of Rust's solution, with Result types and various macros/methods which can do the commmon stuff for you

Re: You’re better off using Exceptions

#70

My problem with exceptions isn't so much exceptions themselves but the way they're used. The way I see it, exceptions should only be used for things that are irreconcilable, which most of the time is interpreter errors(e.g. undefined is not a function). In other words, I don't think it's that common that custom exceptions are needed outside of assertions to prevent the developer from doing something stupid. If you ar…

If you expected the record to be found, the failure of finding it is an exception. If it was an open question, then it isn’t. This is why API generally have checks that allow developers to avoid that failure if the failure is expected (eg Record.exists). What you are suggesting is simply a reverse order (check after vs check before). I think check before leads to a much cleaner API than one that dumps a null or failu…

The problem is that these systems are built in a way in which the data access latter is throwing the exception even though it can’t reasonably know if the record is expected to exist or not. It can’t or shouldn’t know that this is an invalid program state. Specifically, if exceptions are being used properly, you should almost never need to use try/catch.
Post reply on HN