Live data from Hacker News

You’re better off using Exceptions

eiriktsarpalis.wordpress.com

51–60 of 242 posts

Re: You’re better off using Exceptions

#51

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 failure code instead.

Re: You’re better off using Exceptions

#52

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 data file and if it's not an integer then something terrible has happened. Alternatively, you would use TryParse() for user input knowing that users will definitely not be trusted to always type a number.

Not having non-throwing versions of these methods (e.g. Java) means you lose the ability to signal intent and you have to do a lot of pointless catching of exceptions.

Re: You’re better off using Exceptions

#53
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 felt the same way about Go's error handling, or lack thereof, which forces you to implement your own error handling system. But as it turns out, if you are forced to do that, you will create an error handling system that is easy to follow with zero GOTOs (as is the case with exceptions). Although it makes Go code a little more cumbersome to write, the trade-off is that when you read Go, you're never unsure as to where the "code path" is, it's very clearly laid out for you.

Re: You’re better off using Exceptions

#54
post #48
post #19

Earlier quoted context omitted.

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 problem with checked exceptions as implemented in Java is that not all exceptions are checked, but all error handling uses the same mechanism. Midori nicely separated panics (programmer or system errors) from exceptions. Panics _could not be caught_ - they crashed the process. (Processes were therefore really cheap in Midori). Java, on the other hand, put common programmer errors into the exception category in or…

And for those who are interested in this kind of thing, check out Zig's return traces (a kind of inverted stack trace) for other good ideas on how to do exceptions in a new way:

* https://ziglang.org/documentation/master/#Error-Return-Trace... * https://ziglang.org/#A-fresh-take-on-error-handling

Re: You’re better off using Exceptions

#55

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 long time.

Re: You’re better off using Exceptions

#56
post #46

Earlier quoted context omitted.

It's not clear if you are continuing to refer to Rust as your parent post did, but if so, note that this is not the standard Rust meaning for "unsafe". Using it in such a way makes it more complicated to discuss and explain the Rust-specific meaning.

If Rust devs took an everyday English word and gave it a different meaning, isn't it their fault when they have to train everyone into discarding their intuitions? It sounds like it means “code that is unsafe for a particular reason”; name the reason and leave developers capable of criticising code that is unsafe for other reasons, too. Unchecked Exception throwing code and stringly typed code are both unsafe. The wo…

> If Rust devs took an everyday English word and gave it a different meaning

Perhaps, but if we had come up with a new word, you or someone else would complain that we had done that instead of using a word that people already "understood". :-)

English is a language full of elision, and there's nothing inherently wrong with using one word for closely related meanings. When being precise, Rust uses the term "memory unsafety", but we humans usually shorten that to just "unsafety" because we are lazy.

My point was merely to state that a function throwing an exception [1] doesn't introduce memory unsafety.

---

[1] Notably, we call this "panicking" in Rust-speak; does the fact that we call it something different from "exceptions" confuse people? Probably at least one.

Re: You’re better off using Exceptions

#57
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 haven't written very much Java, but here are some differences between Java checked exceptions and Rust errors as I understand them:

In Java, a function may throw a long list of checked exceptions, and these lists tend to grow to inconvenient sizes in larger programs. For example, if foo() calls bar() and baz(), which each throw 3 different exception types, then now foo() might throw 6 different exception types. In contrast in Rust, each function can only return 1 error type. If a function needs to represent several different types of internal errors, then the crate that it's in needs to define an error enum type with a variant for each of those. (Either that, or the function can use a generic wrapper error that can contain anything. This is less common in library code but pretty common in application code.) This shifts a lot of work from library callers to library authors, which is a good thing.

Someone with more Java experience will need to correct me here: I think it's fairly common to bulldoze all that complexity by declaring a function that just "throws Exception". That saves you from writing out N different types (and more importantly, from changing every transitive caller when a low level library introduces a new exception type). But it kind of defeats the purpose of checked exceptions, by throwing away all the info they provide. It's a shame that you have this "all or nothing" choice when it comes to exceptions and how much complexity you want to deal with. In contrast in Rust, wrapper errors can define automatic "From" conversions from the lower level error types they wrap, and the standard `?` operator automatically applies those conversions. That means that in many cases, a low level library adding a new error variant might not require any changes in its callers at all. The new information is there for callers who want to look for it, but existing abstractions around the error type generally just keep working.

Re: You’re better off using Exceptions

#58
post #48
post #19

Earlier quoted context omitted.

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 problem with checked exceptions as implemented in Java is that not all exceptions are checked, but all error handling uses the same mechanism. Midori nicely separated panics (programmer or system errors) from exceptions. Panics _could not be caught_ - they crashed the process. (Processes were therefore really cheap in Midori). Java, on the other hand, put common programmer errors into the exception category in or…

Midori's really interesting. I'll just leave the link to Joe Duffy's blog on the Midori error model: http://joeduffyblog.com/2016/02/07/the-error-model/

Re: You’re better off using Exceptions

#59
> It’s by such misadventure that the working F# programmer soon realizes that any function could still potentially throw.

That's your problem right there. "Invisible control flow", as Joe Duffy puts it.

http://joeduffyblog.com/2016/02/07/the-error-model/#unchecke...

What's needed are two distinct error mechanisms: panic/abandonment for unrecoverable errors (which can happen at any time), and then for recoverable errors, either checked exceptions in some flavor (including Swift and Midori's untyped `throws`) or Result types.

Once you eliminate invisible control flow, you're no longer "better off using Exceptions".

Re: You’re better off using Exceptions

#60

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…

It all depends on context. I believe that's why python for example throws an exception if given key doesn't exist when you use `dictionary[key]` but also gives you option to call `dictionary.get(key, [value])` which returns `None` or `value` (if specified) if the `key` doesn't exist.
Post reply on HN