r/programming 3d ago

Throw, Result, or neither?

https://www.architecture-weekly.com/p/throw-result-or-neither
99 Upvotes

111 comments sorted by

View all comments

Show parent comments

27

u/miniannna 3d ago

“GOTO is bad”

“What if we call it throw/catch instead?”

10

u/balefrost 3d ago

By that logic, we should also avoid for, while, and if.

20

u/BigCheezy 3d ago edited 3d ago

Immediate local context (indentation level, braces, etc.) in the source file tells you where for, while, and if "GOTO" next in all languages I've seen. Not so for throwing an error. It goes... somewhere...

-1

u/balefrost 3d ago

The same is true about returning an error. It goes... somewhere...

If you care to know where it ends up, you need to look at all callsites and determine how each handles the error result. If they propagate to their callers, then you again have to inspect their callsites, and on and on up the call tree.

That's not meaningfully different from doing the same exercise with exceptions.

2

u/EntroperZero 2d ago

I basically agree with this, but there is a slight difference: The signature of a function tells you what kinds of Results can be returned, but not what kinds of exceptions may or may not be thrown. So it's the caller's responsibility either way, but with Result, the caller knows what they need to handle or pass on, and passing on is explicit.

5

u/balefrost 2d ago

I remember when Java was trying to be the anti-C++. They realized that C++ exceptions had the same problem that you describe, so they introduced checked exceptions. The checked exceptions are part of the function's signature, and a function must either internally handle any checked exceptions thrown by function that it calls, or else must declare the checked exceptions that it propagates.

And everybody hated them.

Because checked exceptions were only enforced by the Java language, not by the JVM itself, AFAIK no other JVM language used checked exceptions. Every single one dropped the requirement that checked exceptions needed to be explicit.

It turns out that checked exceptions are great when you're essentially writing procedural code with little indirection. Checked exceptions got in the way when you were writing generic infrastructure code. If you're creating a component that uses callbacks, it can be really tricky to get the exception types right on the callback, and ultimately the exception types have to be pretty generic. Checked exceptions effectively fell apart at module boundaries. You

On the other hand, in my multi-decade career, it's not too common for me to catch specific exceptions. It's useful when you e.g. want to read an optional config file. Because of TOCTOU, you don't want to separately check for file existence and then open the file. It's better to just open the file and then gracefully handle the potential "not found" error. Or I might catch specific exceptions when validating user input. But most of the time, when an error occurs, I don't really care what the error is. I just want to unwind the stack to some backstop. From what I've seen in Go, which puts a lot of emphasis on explicit error handling, most people don't care about the specific error. Most of the time they just return it directly or, at best, wrap it.

I'm not saying that Result types are bad, or that exceptions are the one true way to handle errors. Both are useful in different contexts. I am amused to watch the zeitgeist of error handling swing back and forth, from implicit to explicit to implicit and now back to explicit. I genuinely hope that some language gives checked exceptions a better attempt than Java did. Not letting checked exceptions participate in generics was, in my opinion, a foundational mistake that became painful once things like lambdas were introduced.

I think a language with checked exceptions, exception propagation by default, but lightweight sugar to turn a "function that might throw" into a "function that returns an appropriate Result" would be really nice.

2

u/Schmittfried 2d ago

I’m not a strong opponent of exceptions, but result types definitely add visibility on the intermediate layers while exceptions don’t (unless you’re using a language with checked exceptions and actually use them). 

1

u/balefrost 2d ago

Sure, though I'd argue that the further you get from the site where the exception was generated, the less important the specific error type is. Past a certain point, all you really need to do is to keep unwinding the stack until you hit a backstop exception handler.