Live data from Hacker News

Why checked exceptions failed

borretti.me

291–300 of 318 posts

Re: Why checked exceptions failed

#291

Earlier quoted context omitted.

You must have a real panic when you see a sign saying “No parking except weekends.” Weekends happen all the time!

So if you write code that handles dates you'd throw NotWeekendException to notify the caller that it's not weekend? Exceptions should be for exceptions, not control flow.

It says the word exception right there on the sign.

People keep parroting “exceptions should be for exceptions” like it means anything. Just because when it was first used it was given a particular name doesn’t really tell you anything about how it should be used.

Re: Why checked exceptions failed

#292

Earlier quoted context omitted.

Are we comparing the same things? Adding exceptions to the method signature is pretty explicit to me too. It's also pretty ergonomical depending on how you generally treat errors you don't care about. I do find your point about exceptions being for unexpected things interesting: basically, split errors into two classes and use separate mechanisms for each. I generally feel that this differentiation would never hold b…

> FWIW, my take is that they are largely equivalent except for more or less syntactic support for the approach. Yeah, as with lambda calculus and turing machines, they are equivalent in capacity. > Are we comparing the same things? Adding exceptions to the method signature is pretty explicit to me too. Maybe, maybe not. IME the IDE support for exceptions is quite a bit worse than for returning results and such. > I d…

> I don't quite agree with that, as with encoding it in the type system conveys more intentionality than with exceptions, IMO.

Sure, but why keep using exceptions then at all? I am fine with returning errors making them explicit, but I would avoid exceptions everywhere (Go-style).

Re: Why checked exceptions failed

#293

Earlier quoted context omitted.

This comes from a misunderstanding of the reason why exceptions where designed they way they were. The whole point of exceptions bubbling up w/o having to write support code to deal with passing exceptions further is to make it so that the purpose of the function is clear to the reader. Go's exceptions have the same unfortunate property as Java's checked exception. And that's what makes Go's code atrocious. Every oth…

No. This comes from a misunderstanding of checked exceptions. Checked exceptions don't mean I need to handle the exception right now. They mean I need to either do that or declare throws. Declaring throws is fine it implicitly documents the code and enforces a similar requirement up the chain. Checked exceptions aren't the default and shouldn't be.

> Checked exceptions don't mean I need to handle the exception right now.

Yes it does. You either use try-catch-catch-...-catch, or you append the new exception to the ever growing list of exceptions your function might throw. Even worse: when two functions called by the function you design can throw the same type of exception but for different reasons (eg. two functions cannot find a file, but those are different files), then, if you were a diligent and mindful programmer, you'd have to catch both and re-throw with new types, so that upstream could differentiate between the two failures, adding even more crutft into your code.

Re: Why checked exceptions failed

#294

Earlier quoted context omitted.

No. This comes from a misunderstanding of checked exceptions. Checked exceptions don't mean I need to handle the exception right now. They mean I need to either do that or declare throws. Declaring throws is fine it implicitly documents the code and enforces a similar requirement up the chain. Checked exceptions aren't the default and shouldn't be.

> Checked exceptions don't mean I need to handle the exception right now. Yes it does. You either use try-catch-catch-...-catch, or you append the new exception to the ever growing list of exceptions your function might throw. Even worse: when two functions called by the function you design can throw the same type of exception but for different reasons (eg. two functions cannot find a file, but those are different fi…

If it's an evergrowing list then you're using checked exceptions wrong and they highlight to you the problem of too many responsibilities in a single application.

Notice that IOException is one exception, you don't need to declare FileNotFoundException because it is an IOException. There's a similar hierarchy in an SQLException.

That's part of the beauty of checked exceptions. If your throws statement becomes too long or its stack carries too deep then you know you have a problem. This would be hard to notice otherwise.

Re: Why checked exceptions failed

#295

Earlier quoted context omitted.

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 int…

This is a problem of dispatch. Not so much of type inference... The problem with dispatch says that if a method gets overloaded too much and too often, then programmers tend to make mistakes when they assume how the method they call will work.

You should be insane if your program accidentally confuses people with missiles, but I understand that this is a stretch to amplify the point. What tends to happen in practice is that eg. the same method which used to only read something from the local storage gets a new overload that goes out into network, and brings with it a whole new bunch of problems the calling code wasn't prepared to handle. Or, when a string was passed to the method that used to do something simple, and then the method gets overloaded with a more sophisticated method that interprets substrings in the passed string as commands to run some code -- and then you get security problems.

Have you ever seen the IntelliJ interface when it deals with Rust code? I'm not sure if it does the same for other languages with type inference feature. Anyways, the idea here is that the programmer can toggle the display of inferred types to qualify every expression. So, it's really trivial to make sure you aren't calling fire() of a missile instead of an employee. And, in practice, this doesn't lead to problems. This is so because dispatch, essentially, blurs the difference between multiple different objects, while type inference is just a kind of abbreviation. It may cause confusion, but it will be of a different type: the reader might not know what's being abbreviated, whereas with dispatch, the reader may be convinced they know what the author meant, but still be wrong.

Re: Why checked exceptions failed

#296
post #120

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…

> Will you require that the acceptable functions only throw exceptions that you like? -- Then your generic function is close to being worthless... Constrained generic parameters are actually super useful. > If exceptions are encoded in function's interface, then they have to be in ABI They already are in Itanium > you cannot serialize the communication using some protocol with a fixed number of types (eg. JSON and fr…

> Constrained generic parameters are actually super useful.

Then you missed the main point: if you require the generic function to accomodate all sorts of kinds of exceptions raised by the functions it may call, this requirements now propagates to every function it may call. So, you end up implementing functions with unnecessary "throws" because they might be used in a generic function which had to add that clause because of some other completely unrelated function.

Alternatively, you aren't writing generic code at all, you just write two implementations which happen to have similar names.

Re: Why checked exceptions failed

#297

Earlier quoted context omitted.

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.

In the case of map function hopefully you're using it with methods that don't fail in serious ways, and don't need strong error recovery. If so Java has RuntimeException to handle that case. If serious errors are possible and strong error recovery is needed, then you need to avoid the conveniences offered by functional style programming.

Sorry. This is nonsense. map() is the bread and butter of any program. Besides, you cannot ever decide whether an exception is important or not -- it's always in the purview of the user.

Re-throwing a non-checked exception is what I described as the usual / typical coping mechanism in languages with checked exceptions. Which is obviously a way to negate the whole feature.

Re: Why checked exceptions failed

#298

Earlier quoted context omitted.

So if you write code that handles dates you'd throw NotWeekendException to notify the caller that it's not weekend? Exceptions should be for exceptions, not control flow.

I'm curious how this is possible? Exception throwing and handling is fundamentally a flow control construct. ie: throwing an exception must control flow. A counter-example snippet where throwing an exception does not control flow would be appreciated.

An exception would be if someone tried to get the parking status for "Blarghsday" from the function or some other impossible state (We all know time is weird[0])

If the expected operation is to return parking allowed status for a specified date or a weekday, I'd expect the function to return true or false unless the input is malformed (Actually I'd prefer it to return some kind of object that can give more context to the true/false, but I digress).

During normal operation it should never throw an exception. Because if I get an exception, I'll most likely either throw it up the stack or log an error, which will ping someone in PagerDuty if it happens too often.

[0] https://gist.github.com/timvisee/fcda9bbdff88d45cc9061606b4b...

Re: Why checked exceptions failed

#299

Earlier quoted context omitted.

If I need to write some bytes to an S3 bucket but the network is hosed, there's literally nothing useful I or any library can do until the network is back up. RPC calls will fail, error logs should get written, and a monitor should get triggered, and someone should get paged so they can wake up and figure out why the network is hosed. Nowhere in there is it useful for me to wrap all my S3 writes in try/catch blocks.

Error logs and monitor needs to known the operation failed somehow, try/catch or return value. > literally nothing useful I can do For some services, for others queuing the operation for retry is a thing.

Error logs and monitors find out because the RPC fails, which causes an error to be logged and a failed request metric to be incremented. (The UncaughtExceptionHandler will do the same for stuff failing in background threads.)

If eventual consistency is important, enqueuing for retry has to be done BEFORE you try to write, not on write failure. If/when the write succeeds, you remove the item from the retry queue.

Re: Why checked exceptions failed

#300

Earlier quoted context omitted.

If constructing "out" fails but one of the catch-blocks tries to use "out", what should happen?

Python is an example of a language that works like this. When the constructor throws, 'out' remains not defined, but you can just do 'out = ...' in the catch block and define one with a fallback value. So all the code after the error handing would just see a working 'out' variable. This works due to all variables being bound to the function scope, not to the code block, in Python.

Python can do that because:

* it's not an error to have an unbound name in scope; just referencing it at runtime is an error. * there is a reasonable default; anything can be set to None

This doesn't hold in C++. If your class throws during its initialization, you can't really do much (even default initialization of members may not work). Reassignment may not be possible if it was declared const.

And there's still the issue of 'which objects successfully initialized'?

Post reply on HN