Live data from Hacker News

Why checked exceptions failed

borretti.me

171–180 of 318 posts

Re: Why checked exceptions failed

#171
post #66

I have extensive experience in C# as well as Java. It is bizarre to suggest that checked exceptions have failed. It is unchecked exceptions that have failed. It is the biggest flaw of C#, in fact. Why? As an example, I wrote some very good C# code, carefully tested it, made it work flawlessly, then suddenly it started crashing. What happened? Someone made a change in a function I was calling, and it started throwing…

I stopped using Java a long time ago, and so I assume the language has gotten better since then, but early on at least it felt like Java almost took pride in making the developer jump through extra hoops. Compared to many other languages, using Java just made me feel tired. Checked exceptions - a feature that seems to be a cost to the developer 100% of the time while being a benefit far less than 1% of the time - is…

> Checked exceptions - a feature that seems to be a cost to the developer 100% of the time

That's because exceptions are overused for not-truly-exceptional conditions. Languages that throw exceptions when a dictionary does not have a key you're looking for are doing it wrong.

Re: Why checked exceptions failed

#172

Earlier quoted context omitted.

This is very simplistic view of the problem. This completely glosses over modularity, ABI, performance optimizations... just to name a few. How are you going to write generic functions that take functions as arguments and re-throw the errors thrown by these functions, if you use checked exceptions? Will you require that the acceptable functions only throw exceptions that you like? -- Then your generic function is clo…

> write generic functions that take functions as arguments and re-throw the errors thrown by these functions There is a philosophy that applies here: simple things should be simple, complex things should be possible. The scenario you're mentioning is not common enough that the language design should be centered around it.

It's a very common pattern, almost every modern language has a "map" function. The map function can throw a superset of the exceptions that its argument can throw. If checked exceptions can't deal with this, they'll be of limited use.

Re: Why checked exceptions failed

#173

Earlier quoted context omitted.

The library knows which are crucial issues that warrant your attention. A checked exception is a regular exception, it's just one that you can't miss and must either handle or propagate. As a library author if you don't feel you need it then don't use it. It's optional. That's the beauty of it. > First thought: documentation. (which is required for both, checked and unchecked exceptions). Documentation > But overall,…

> The library knows which are crucial issues that warrant your attention The library author can’t know what’s crucial in the context of my program.

This feels argumentative but fine.

If you're unsure then make it a runtime exception. I agree that a lot of the problems people have with checked exceptions is that people over use them.

You don't want to handle the checked exception wrap it with a runtime exception. But as an author if there's something important, I want to give the user of the library as much help as I can.

Re: Why checked exceptions failed

#174
post #67

Checked exceptions are used to make up for Java's inability to return more than one value, plus it's inability to wrap two values without defining a new type. In other words, I think checked exceptions are basically a symptom of a lack of object literal syntax. This is in addition to their status as a "cool language feature" that is a siren song to new, bright programmers looking to spice up their designs. Exceptions…

FYI: With Java 21 (2023/09/19) this is finally possible. Relevant JEPs: - 441: Pattern Matching for switch - 440: Record Patterns - 409: Sealed Classes - 395: Records It is kind of similar to Scalas version of pattern matching with case classes.

And it won't get adopted any time soon due to backwards compatibility and existing code. Anybody who wanted to use it used vavr at this point.

Re: Why checked exceptions failed

#175
post #152

Earlier quoted context omitted.

Crazy idea: Maybe it would be helpful if we could label operations, and catch by either label or type or (label, type) . The we could centralize error handling without losing anything.

While deceptive at first... Just try to imagine how "extract method" refactoring would work...

It would have to do some clever rewriting of the logic or it could simply declare that extracting method isn't available on that region. The simplest way to rewrite the logic may be the introduction of new exception type(s) corresponding to the labels.

Re: Why checked exceptions failed

#176

Earlier quoted context omitted.

Imagine that the functionality implemented by your method is very important. This functionality should not be needlessly aborted. If so you want to be aware of errors you can recover from, correct? This is why checked exceptions are helpful. It gives you a guaranteed-by-compiler list of exceptions and you can decide which of those you should recover from.

Or I can catch any exception out of the codepath I'm concerned about, examine it to see if it's one of the known set of exceptions I intend to handle, and then either do so or rethrow it. If there's a benefit to compile-time exception checking over this method, I have to admit I don't see it. But I've also never worked deeply enough with Java to be familiar with the nuances of its exception handling, so that may be w…

The problem is that handling arbitrary errors can be very complex. It's easy to make errors in the error handling code. Especially if the error you are handling never occurs -- because there's no way to test error handling code for an error that never happens.

That's why it is really useful to know when a call can fail, and what kinds of errors you have to expect.

If you always have to add a generic error handler for possible unknown errors, then you'll write a lot of untested, dead code.

Re: Why checked exceptions failed

#177
post #29

Little aside, but I feel a lot of the drama surrounding exception could have been solved with a little syntactic sugar making their handling easier. Something along the lines of Perl's "|| die("...")" pattern would be a start (i.e. add some context and rethrow). In C++ I find it quite infuriating that try{} opens up a new lexical scope, which means you can't construct something, check for errors and move on, since th…

> In C++ I find it quite infuriating that try{} opens up a new lexical scope, which means you can't construct something, check for errors and move on You technically can with a small workaround (demonstrated below), though I personally wouldn't use this approach. void foo() { auto value = [] { try { return Foo(); } catch (...) { // Something here } }(); value.do_something(); }

Yep, I had to resort to that a few times. With a bit of syntactic sugar that could be turned into something like:

    auto value = try Foo("will fail") 
    catch(...) {
        return Foo("will work"); // or throw something else
    };

Re: Why checked exceptions failed

#178

Earlier quoted context omitted.

Some people say the same about strong typing. Like, why do I have to write down the type of every single parameter or variable? Java is making me jump through hoops! The point is, if you don't need the rigor of a strongly typed compiled language, there are other languages you can use. Perhaps a bash script is all you need.

You are very confused... "strong" in strong typing doesn't mean you have to write much or at all. Actually, it doesn't mean anything really. But, let's say, Haskell is probably at least as "strongly typed" as Java -- at least that's how most people understand that wording. And you don't have to write types in Haskell at all. It will be a nightmare (as if Haskell can be anything else, but even by the very low Haskell…

Type inferencing can get you in trouble quickly. Consider this code:

   var fireable = someMethod();
   firable.fire();
The programmer intended this code to fire an employee. Let's say this code is in a military application, and another programmer modified the someMethod() function to return a missile. As long as the missile object has a fire() method this code will compile just fine... and do something the code didn't intend to do.

How likely are you to have employee firing and missile firing in the same program? Not very likely, but the principle is valid, regardless. You need to express your intention more clearly like this:

   Employee fireable = someMethod();
Now if someMethod() is modified to return a missile you get a compilation error, and the world will be a lot safer. You don't want missiles being fired by accident!

Re: Why checked exceptions failed

#179

Earlier quoted context omitted.

I'm not smart enough to parse this. Try again?

"All non-primitive values are nullable references" is a feature of the language. You posted that you are trying to avoid using that feature (instead using non-null references to a special Null value?) and trying to avoid having null references for the types you create. It seems like you do not actually think the feature is a good feature.

> Ditto @Nullable and @Nonnull.

I was referring to the annotations. My proposal moots them.

References would still be nullable.

Re: Why checked exceptions failed

#180
post #21

Earlier quoted context omitted.

> Someone made a change in a function I was calling, and it started throwing a new exception. If it has nothing to do with your code, why not either let it bubble up the stack or try/finally it to do whatever clean-up you need to do before re-throwing it and letting it move on to a global logger or similar. If it is something you care about you can always catch the specific exception type and handle it. Maybe whoever…

Imagine that the functionality implemented by your method is very important. This functionality should not be needlessly aborted. If so you want to be aware of errors you can recover from, correct? This is why checked exceptions are helpful. It gives you a guaranteed-by-compiler list of exceptions and you can decide which of those you should recover from.

This is one of the main reasons why I personally try to avoid exceptions and instead encode failure into the type system. For example, returning a Result rather than just a 't. (You can refine the type further). Altough, in most languages that approach results in a lot of boilerplate.

In F# it works quite well, though.

Post reply on HN