If I uncomment the line "Scanner line..." I get an error "FileNotFoundException"

If the program can see that the file exists, why can't "Scanner" find the file? I've been Googling for the last half hour trying to figure this out. Every answer I see (most form Stack Overflow) just say to check upper- and lower-case letters and to specify an absolute path. I think I've done that. Any other ideas?

HelloWorld.java:12: unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown

That's saying that the java.util.Scanner constructor is marked as being able to throw the exception java.io.FileNotFoundException - you either need to wrap that in a try/catch or mark your function as being able to throw that exception. It's not actually being thrown (you're seeing a compile-time error, not run-time).

Ok. I fixed it by adding "throws FileNotFoundException" in the main declaration. I'm not far enough in my Java studies to understand the "throws" keyword in method declarations. If someone could explain why that's necessary, or I can wait until I'm further in my studies.

Checked exceptions make the compiler reason for you about which types of errors can happen at each point in the program, just as the compiler checks types of values against variables to which the values are assigned to ensure type safety. In both cases, having the compiler do the tedious work to check correctness of your program is a good idea. Unfortunately, in Java, implementation in both cases requires writing a lot of boilerplate: in the former case you must specify "throws" clauses everywhere a checked exception may be thrown; in the latter case, Java requires you to specify the types of all variables and return types of all methods. The latter case can be solved by having the compiler infer types of expressions by following the flow of the code. Perhaps the former case would be best solved analogously, so that one would only need to provide a "throws" clause where one wants the compiler to verify one's assumption about what errors can happen or to more clearly document the code.

they're (IMO and IME) egregiously awful if you work with incompetent people.

Those people just go with Pokemon Exception handling, often destroying context like stack frames and messages in the process.

At my last pace of work it resulted in truly dire anti patterns of all kinds as muppets thrashed at their keyboards till their compilers shut up.It was a while until I was proved sufficiently on the ball to get rid of those layers, and unwrapping it was horrid.

IMO the biggest problem with checked exceptions in Java is in inheritance hierarchies: a general interface must either declare all possible exceptions thrown or implementors must wrap those exceptions. A partial solution would be to allow declaring in a "throws" clause any type parameter extending Throwable so that the interface could parameterize an exception thrown. Another partial solution would be to specify to the compiler to not check a given exception, so that it may bubble up as an unchecked exception (so checked vs. unchecked would not merely be a function of the exception's class but would additionally be a function of location in the code).

So the gist I'm getting as a result of replies and Shuggy's links is that Java methods have a modified Murphy's Law: If anything can go wrong with this method, note it in the declaration. Because the method I wrote might throw a FileNotFound exception, I have to state the possibility in the method's deifnition. Checked exceptions won't keep a method from producing an exception, but they allow me to write a catch block into any code that calls that method.

That's probably not exactly right, but am I on the right path?

If I understand correctly, I can get around this problem in the future by just adding "throws $whateverCompilerErrorIGot" in the first line of the method? Do you sometimes end up with:

So the gist I'm getting as a result of replies and Shuggy's links is that Java methods have a modified Murphy's Law: If anything can go wrong with this method, note it in the declaration. Because the method I wrote might throw a FileNotFound exception, I have to state the possibility in the method's deifnition.

Well, of course there are unchecked exceptions and there are bugs or other issues that unfortunately don't produce exceptions. And you don't have to mention exceptions that couldn't possibly bubble out of the method - ones you catch and don't rethrow.

Quote:

Checked exceptions won't keep a method from producing an exception, but they allow me to write a catch block into any code that calls that method.

You can write a catch block for any exception, but you typically don't want to catch unchecked exceptions - that's why they're unchecked.

Quote:

If I understand correctly, I can get around this problem in the future by just adding "throws $whateverCompilerErrorIGot" in the first line of the method? Do you sometimes end up with:

Yeah but that's not always the best way to solve the issue. Often you want to "wrap" the exception in an unchecked exception. For example, if you know an IOException will never be thrown, you can do the following:

Code:

try { byte[] data = ...; doSomethingWithAStream(new ByteArrayInputStream(data)); // throws IOException due to passed-in stream but for no other reason} catch (IOException e) { throw new AssertionError(e); // this should never happen}

This way you don't have to wrongly state that an exception will be thrown - instead, you wrap the exception in an unchecked error that will make it obvious if for some bizarre reason an IOException occurs. (It could occur due to your failure to read the documentation of doSomethingWithAStream.)

For example, you know that opening a file could return a FileNotFoundException. However, while it's probably worthwhile to handle it in a GUI application (display the file dialog again), it is not worthwhile to do so in a batch command-line application (because there is no one around to edit the filename).

Only you can make these decisions, and you should make these decisions entirely independently of what the language forces you to do with checked exceptions.

Bagheera wrote:

So the gist I'm getting as a result of replies and Shuggy's links is that Java methods have a modified Murphy's Law: If anything can go wrong with this method, note it in the declaration.

Only if the underlying exception is checked. Not all potential exceptions are.

Quote:

Checked exceptions won't keep a method from producing an exception, but they allow me to write a catch block into any code that calls that method.

You can write an exception handler regardless of the throws clause, and will have to do so whenever you want to catch anything that descends RuntimeException (the unchecked exceptions). Depending on what libraries you use and what code you write, you may do that anywhere between "never" and "almost always".

Quote:

If I understand correctly, I can get around this problem in the future by just adding "throws $whateverCompilerErrorIGot" in the first line of the method? Do you sometimes end up with:

If it's a checked exception, yes. Most people either let their IDE compute a throws clause for them, or just write 'throws Exception' which makes the compiler happy and doesn't cause any real, practical harm.

What causes harm is the great lengths people go through to contort stuff to the way they like, instead of just doing the simplest thing possible.

Checked exceptions make the compiler reason for you about which types of errors can happen at each point in the program,

It most certainly does not. It merely verifies that you've either handled the exception or passed the buck. The ability to always pass the buck is precisely why checked exceptions are pointless, because who cares what exceptions could be thrown if you never catch any of them? The end result is always the same.

The interesting question is never "What exceptions could I handle?" but rather, "What exceptions must I handle?" Compilers can only help us answer the former question, not the latter question. Hopefully we'll have found better use for our CPU cycles by the time computers can answer the latter question.

Quote:

IMO the biggest problem with checked exceptions in Java is in inheritance hierarchies: a general interface must either declare all possible exceptions thrown or implementors must wrap those exceptions. A partial solution would be to allow declaring in a "throws" clause any type parameter extending Throwable so that the interface could parameterize an exception thrown.

Parameterizing throws clauses only makes sense if the type itself is parameterized, which is already supported well-enough. Otherwise, it does nothing useful, because you still need the concrete type in order to catch the exception and meaningfully handle it. That need is an automatic LSP violation.

Quote:

You can write a catch block for any exception, but you typically don't want to catch unchecked exceptions - that's why they're unchecked.

This entirely depends on the library in question.

Quote:

Yeah but that's not always the best way to solve the issue. Often you want to "wrap" the exception in an unchecked exception. For example, if you know an IOException will never be thrown, you can do the following:

While there are legitimate situations for nesting exceptions, "knowing" that an exception can never occur is not one of them.

It most certainly does not. It merely verifies that you've either handled the exception or passed the buck. The ability to always pass the buck is precisely why checked exceptions are pointless, because who cares what exceptions could be thrown if you never catch any of them? The end result is always the same.

Pathologies aside, the current system essentially enumerates (forces the method to acknowledge) all checked exceptions that can happen in each method. So by requiring you to catch or "pass the buck", the compiler reasons for you about what errors can occur (or you may see it as forcing you to reason—as I suggested above, the compiler could automate this tedious process). It doesn't identify all errors—just certain enumerated ones—which is what I said here.

Quote:

The interesting question is never "What exceptions could I handle?" but rather, "What exceptions must I handle?" Compilers can only help us answer the former question, not the latter question. Hopefully we'll have found better use for our CPU cycles by the time computers can answer the latter question.

So long as what exceptions must be handled is a function of the procedure generating the exceptions, not a higher level business constraint, the procedure can take a callback procedure for any exception that must be handled. Then the compiler needs only check that a callback is specified whenever the procedure is called, which it can already do.

Quote:

Parameterizing throws clauses only makes sense if the type itself is parameterized, which is already supported well-enough. Otherwise, it does nothing useful, because you still need the concrete type in order to catch the exception and meaningfully handle it. That need is an automatic LSP violation.

I was talking about throwing parameterized types. I didn't realize that an exception type can be a type parameter - thanks for the info. But even in the case of non-parameterized types, covariant throws clauses are both supported and useful and don't violate LSP.

Quote:

This entirely depends on the library in question.

I was speaking broadly. Of course in certain more specific cases, the general "heuristic" might not hold.

Quote:

While there are legitimate situations for nesting exceptions, "knowing" that an exception can never occur is not one of them.

Then what exactly should one do in that situation, eat the exception? Throwing an AssertionError notifies the programmer if his/her assumption was wrong instead of silently failing.

Pathologies aside, the current system essentially enumerates (forces the method to acknowledge) all checked exceptions that can happen in each method.

Calling a bit of bookkeeping "reasoning" is pretty far fetched. Likewise, claiming that checked exceptions are adding to code correctness is equally far fetched, for the reason that I already stated. Passing the buck is always a valid response, hence they're pointless.

Quote:

So long as what exceptions must be handled is a function of the procedure generating the exceptions, not a higher level business constraint, the procedure can take a callback procedure for any exception that must be handled.

And if whether to handle the exception is not a function of the procedure generating the exceptions? What then?

Quote:

Then the compiler needs only check that a callback is specified whenever the procedure is called, which it can already do.

Actually it can't, but whatever.

Quote:

I was talking about throwing parameterized types. I didn't realize that an exception type can be a type parameter - thanks for the info. But even in the case of non-parameterized types, covariant throws clauses are both supported and useful and don't violate LSP.

Covariant throws clauses is not "throwing parameterized types" and are already supported.

Quote:

Then what exactly should one do in that situation, eat the exception?

Declare it and let it happen. The fact it happened is a bug, so throw it upward and hope it crashes the application like it should.

Calling a bit of bookkeeping "reasoning" is pretty far fetched. Likewise, claiming that checked exceptions are adding to code correctness is equally far fetched, for the reason that I already stated. Passing the buck is always a valid response, hence they're pointless.

Checked exceptions add to code correctness just as type checking does. The user can overrule the system by casting, using raw types, etc. but in reasonable programs, it goes a long way. With exception checking you can do similar things: make every method declare "throws Throwable", eat exceptions, etc. but you have to explicitly opt out of the system. Nothing about passing the buck makes checking exceptions pointless.

Quote:

And if whether to handle the exception is not a function of the procedure generating the exceptions? What then?

Then the calling procedure must make that decision and the language must not force it either way. Java's implementation of checked exceptions typically forces the calling procedure to explicitly make that decision (of course you can find exceptions to that rule, such as if the same exception is thrown by multiple method calls).

Quote:

Actually it can't, but whatever.

Sure it can: it requires that there are arguments for all parameters, including callbacks (and, if you want to be pedantic, require that the relevant arguments are non-null, which can be done by making the type non-nullable and doing nullability tracing in the type system).

Quote:

Declare it and let it happen. The fact it happened is a bug, so throw it upward and hope it crashes the application like it should.

That's ridiculous. If an IOException were to occur, that would indicate a programming bug, which can't reasonably be accounted for at a higher level, so why allow the checked exception to propagate? An AssertionError is more appropriate.

Declare it and let it happen. The fact it happened is a bug, so throw it upward and hope it crashes the application like it should.

That's ridiculous. If an IOException were to occur, that would indicate a programming bug, which can't reasonably be accounted for at a higher level, so why allow the checked exception to propagate? An AssertionError is more appropriate.

As for declaring it and letting it happen, yes you can do that and modern IDEs are very good at letting you do so the entire way up the call stack, but just because you can doesn't mean you should and it's horribly invasive. I personally don't like shitting throws clauses over other people's code, though lord knows it's happened to me a ton. Sometimes it's necessary and the right thing to do, but not always, especially if you're programming a library. If you know the situation is irrecoverable, don't make the higher level stuff care about your low level bug. Throw something that will crash the program or throw something like a custom exception that a higher level knows is a Big Deal and can do something (like restart a service or kill an instance or fire off an email).

If you have no intention of ever catching any exceptions (except perhaps as last chance 'do some very detailed logging then let the whole thing die') then they actively hurt you with wasted time.

Even better they don't adapt well over time (if you change a method to no longer throw a certain exception but have cascaded the original throws clause elsewhere then you cause yourself more pain untidying this (or not spotting that such a thing has happened at all)

If it was that good a thing at least one other language would have copied it (that's what people do with programming languages after all), so far none have.

It also plays merry hell with IoC like behaviour, since you are fundamentally passing arbitrary functions[1] so to use checked exceptions there you either wrap any checked ones within the passed in function (messy, extra work and verbose) or have specific wrappers for each function wich state the set of all possible 'expected' checked exceptions. This is madness (not that java doesn't make this harder anyway without first class functions).

Checked exceptions in any largeish (or even medium) sized system immediately starts causing all sorts of encapsulation violations. If you simply end up wrapping almost everything in an unchecked exception then why the hell bother with them in the first place, you've just increased your scope for bugs (insidious ones like forgetting to include the nested exception for example).

1. in java wrapped up in a specific interface implementation, hopefully anonymously

As I explained in my last response to LH, exception checking reconciles what could actually happen with what the programmer thinks could happen. That alone verifies the programmer's reasoning, increasing correctness.

Quote:

If you have no intention of ever catching any exceptions (except perhaps as last chance 'do some very detailed logging then let the whole thing die') then they actively hurt you with wasted time.

Even better they don't adapt well over time (if you change a method to no longer throw a certain exception but have cascaded the original throws clause elsewhere then you cause yourself more pain untidying this (or not spotting that such a thing has happened at all)

You're assuming that you always have to declare checked exceptions. My first post in this thread suggests that the compiler traces them through the flow of the code and only generates an error if the programmer adds an incorrect "throws" clause, avoiding the boilerplate. And when you do want the compiler to check your assumptions, you do want a change in the specification to require a change in your assumptions so cascading is a good thing so long as it's restricted to just where you care about it.

Quote:

If it was that good a thing at least one other language would have copied it (that's what people do with programming languages after all), so far none have.

Right, and PHP's popular because it's good.

Quote:

It also plays merry hell with IoC like behaviour, since you are fundamentally passing arbitrary functions[1] so to use checked exceptions there you either wrap any checked ones within the passed in function (messy, extra work and verbose) or have specific wrappers for each function wich state the set of all possible 'expected' checked exceptions. This is madness (not that java doesn't make this harder anyway without first class functions).

Agreed, and this is the same issue as I described in my second post here.

Quote:

Checked exceptions in any largeish (or even medium) sized system immediately starts causing all sorts of encapsulation violations. If you simply end up wrapping almost everything in an unchecked exception then why the hell bother with them in the first place, you've just increased your scope for bugs (insidious ones like forgetting to include the nested exception for example).

Throwing a new exception always changes specification, whether checked or not, so either way it has the same effect on encapsulation. Unchecked exceptions allow you to pretend the specification didn't change even though it did, which perhaps is fine in most cases but isn't always good. Wrapping is largely a symptom of the problem in your previous paragraph and the requirement to always declare checked exceptions.

As I explained in my last response to LH, exception checking reconciles what could actually happen with what the programmer thinks could happen. That alone verifies the programmer's reasoning, increasing correctness.

The only thing that matters is whether the contortions required to follow the rule result in code with fewer or less bugs. Given that this has considerable second order effects simply trying to reason about it isn't going to cut it. I want serious studies on this (using a version of java where the compiler is tweaked to not care about the throws clause)

Quote:

You're assuming that you always have to declare checked exceptions. My first post in this thread suggests that the compiler traces them through the flow of the code and only generates an error if the programmer adds an incorrect "throws" clause, avoiding the boilerplate. And when you do want the compiler to check your assumptions, you do want a change in the specification to require a change in your assumptions so cascading is a good thing so long as it's restricted to just where you care about it.

So you're saying checked exceptions would be fine so long as they weren't actually java's checked exceptions. Since java is the only language I know of that actually has (compile time enforced) checked exceptions this sounds pretty much like you're saying "checked exceptions aren't great, but I have a better, similar model I'm saying is better".

If perhaps you could make it clear which you are arguing for that would help. If you're postulating an alternate model than please make the precise semantics of you model clear.

Quote:

Quote:

If it was that good a thing at least one other language would have copied it (that's what people do with programming languages after all), so far none have.

Throwing a new exception always changes specification, whether checked or not, so either way it has the same effect on encapsulation. Unchecked exceptions allow you to pretend the specification didn't change even though it did, which perhaps is fine in most cases but isn't always good. Wrapping is largely a symptom of the problem in your previous paragraph and the requirement to always declare checked exceptions.

?? If you can't do anything about the exception who cares?

If the value is had in knowing that X previously didn't throw a particular exception but now it might then it's trivial to: A) get that from a diffB) find all references in your code to X and decide whether you want to do anything about it.

How does having different classes of exception help you here? In most cases a specific exception simply won't be handled anyway so you go from (A) straight to 'do nothing'.

Heck if an API decides to change this it implies the API was horribly designed in the first place because it has failed to encapsulate the operation it is performing.

If you have some better plan in your head for this please lay it out more clearly so we can discuss that (albeit without the benefit of many people having had to actually use it and know what effect it had in reality) Such experience is of course anecdotal, but I think many of us have sufficient smarts to extrapolate well from it.

The only thing that matters is whether the contortions required to follow the rule result in code with fewer or less bugs. Given that this has considerable second order effects simply trying to reason about it isn't going to cut it. I want serious studies on this (using a version of java where the compiler is tweaked to not care about the throws clause)

Then we're talking about two different things. I was talking about a specific benefit of checked exceptions, not arguing that they have a net benefit. I don't necessarily think they have a net benefit - I see both benefits and costs and it isn't clear which outweighs which. But perhaps it's because I use checked exceptions to their strengths and not to their weaknesses: I only make an exception checked if it implies a situation that requires accounting for, which is uncommon, and I otherwise avoid them (except as libraries require, usually incorrectly so).

Quote:

So you're saying checked exceptions would be fine so long as they weren't actually java's checked exceptions. Since java is the only language I know of that actually has (compile time enforced) checked exceptions this sounds pretty much like you're saying "checked exceptions aren't great, but I have a better, similar model I'm saying is better".

If perhaps you could make it clear which you are arguing for that would help. If you're postulating an alternate model than please make the precise semantics of you model clear.

Sorry for being unclear. But keep in mind that I never said checked exceptions in their current implementation or my suggested implementation are good - merely that the former have certain benefits and that I believe the latter solve one of the problems of the former. There are still other problems with checked exceptions of either form, which may doom them to being net negatives.

As an aside, when would exceptions be checked if not at compile time? The whole concept of checking is ahead of time, as opposed to the program failing in some unforeseen way at runtime.

My point is that languages survive or die for reasons other than merit, so looking at the established languages as an indication of what ideas are good isn't so meaningful. There are very nice language features that no popular modern language has, such as Haskell's type inference and automatic partial application.

Quote:

?? If you can't do anything about the exception who cares?

If you only use checked exceptions when you can reasonably do something about it, how does that critique apply?

Quote:

If the value is had in knowing that X previously didn't throw a particular exception but now it might then it's trivial to: A) get that from a diffB) find all references in your code to X and decide whether you want to do anything about it.

How does having different classes of exception help you here? In most cases a specific exception simply won't be handled anyway so you go from (A) straight to 'do nothing'.

Heck if an API decides to change this it implies the API was horribly designed in the first place because it has failed to encapsulate the operation it is performing.

It's unreasonable to expect programmers to "reason by diff" on a large project. If I add a parameter to a method somewhere, should the compiler accept code failing to pass an additional argument to the method, forcing me to manually find all usages and add an argument or have my code fail at runtime? The compiler should catch all such issues that it can reasonably identify.

As for an API changing its specification, there are cases when it's useful or necessary to do so, often due to changes in requirements. When I'm using an API whose spec changes in ways likely relevant to me, I want the compiler to force me to acknowledge these changes. ("Relevant to me" may mean that I included an optional "throws" clause and thus opt into the compiler giving me errors due to unhandled checked exceptions.)

Quote:

If you have some better plan in your head for this please lay it out more clearly so we can discuss that (albeit without the benefit of many people having had to actually use it and know what effect it had in reality) Such experience is of course anecdotal, but I think many of us have sufficient smarts to extrapolate well from it.

I don't necessary have a better plan. Perhaps checked exceptions are inherently shit. But I do think they have value and it would be nice to take advantage of that value while dropping the baggage.

Then we're talking about two different things. I was talking about a specific benefit of checked exceptions, not arguing that they have a net benefit. I don't necessarily think they have a net benefit

Right, that wasn't clear to me thanks.

Quote:

As an aside, when would exceptions be checked if not at compile time? The whole concept of checking is ahead of time, as opposed to the program failing in some unforeseen way at runtime.

You can run static analysis post compile a discover the set of possible exceptions that are not handled.OCaml certainly had such a thing. IF someone wants to they could sanity check that a particular type of exception could never made it to the final (terminal) handler. You could certainly add (opt in) annotations that allowed people that cared about such things to use it as a post build step.

Quote:

My point is that languages survive or die for reasons other than merit, so looking at the established languages as an indication of what ideas are good isn't so meaningful.

It's not about whether the language survives, it's whether the component parts of it are passed on, or incorporated sideways into others. Literally it's like vertical and horizontal gene transfer. when new languages come along that clearly flow in part from some older ones (c# obviously inherited much of its initial structure from java, Delphi, C++ etc). Other times languages decide to incorporate elements (often altered) from other ones, like C++ getting limited lambdas (which have been around for years)

If a feature is particularly tied to other aspects of a language then it's harder for it to horizontally transfer, but if it fails to show up in ones which follow vertically it's pretty much an indication that the net worth is viewed as negative.

Java's eventual transition to being largely JIT based for example progressed directly to c#. It was built, from the get go with JITting in mind. Obviously others had done JIT based stuff before this but the success of this in the java community was a clear indication to many descendent languages that this was a good thing.

checked exceptions is up there with "no unsigned integral types" for things that got dropped with nary a murmur.

Quote:

There are very nice language features that no popular modern language has, such as Haskell's type inference

loads of Languages have type inference. I believe ML was the first one to get Hindley-Milner and Haskell followed adding in type classes. Oh, and type inference is in limited use in c# (no constructors, no signature types), later versions of C++, even java is getting it.

Other languages have added (very) limited forms of type classes I would postulate that adding that horizontally is likely to be a non starter to most languages as the changes would be so pervasive as to merit it essentially becoming a new language with syntactic similarities to the old one (e.g. VB6 -> VB.Net)

Quote:

automatic partial application.

loads of functional languages have this, certainly f# does.

Quote:

If you only use checked exceptions when you can reasonably do something about it, how does that critique apply?

If you control both the callee and the caller and you know a particular class of issues is so prevalent that it would merit a checked exception it is far better to write the API so that it instead returns a discriminated union (painful in java/c#/heavily OO based lanaguages I know but you can do your best) roughly:

(Success * Result) | (Failure * Details)

where Result is genericised

If the set of possible failures is bigger than one you can further nest this. If you have a decent pattern matching/switch implementation you can be informed of your failure to deal with a newly added error condition type.

Quote:

It's unreasonable to expect programmers to "reason by diff" on a large project.

I don't see why not. If the thing has changed sufficiently to merit new checked exceptions then there is likely to be far more pervasive changes that the compiler may not be helping you with. The onus is on someone to go and figure this all out. Hoping that the exceptions changing causes this is poor planning.

Quote:

If I add a parameter to a method somewhere, should the compiler accept code failing to pass an additional argument to the method, forcing me to manually find all usages and add an argument or have my code fail at runtime? The compiler should catch all such issues that it can reasonably identify.

But this is not the same thing. There is no reasonable default behaviour for the addition of a new parameter where no default exists. the developer must decide what to do. There *is* a reasonable default behaviour in the vast majority of programming disciplines to a new *exceptional* circumstance. Die, with detail, if not dignity.

If you're doing something where deal with error conditions is so important then checked exceptions are utterly the wrong thing to be using. Way more powerful provably correct tools exist (albeit with much higher cost of implementing). why bother with a half assed solution that is trivial to circumvent.

The key problem with checked exceptions is that the definition of 'must be dealt with' is defined at the exception level, rather than at the method level. At that stage I firmly believe that actually *not using exceptions* at that point is far, far better, albeit this works best when the language can enforce the check that all bases have been covered.

loads of Languages have type inference. I believe ML was the first one to get Hindley-Milner and Haskell followed adding in type classes. Oh, and type inference is in limited use in c# (no constructors, no signature types), later versions of C++, even java is getting it.

Other languages have added (very) limited forms of type classes I would postulate that adding that horizontally is likely to be a non starter to most languages as the changes would be so pervasive as to merit it essentially becoming a new language with syntactic similarities to the old one (e.g. VB6 -> VB.Net)

ML and Haskell aren't new. The point is that languages regressed substantially on type inference: we have a whole slew of new and popular languages and none of them holds a candle to ML or Haskell in type inference.

Quote:

loads of functional languages have this, certainly f# does.

But the vast minority of recent languages don't have it. Languages have regressed.

Quote:

If you control both the callee and the caller and you know a particular class of issues is so prevalent that it would merit a checked exception it is far better to write the API so that it instead returns a discriminated union (painful in java/c#/heavily OO based lanaguages I know but you can do your best) roughly:

(Success * Result) | (Failure * Details)

where Result is genericised

If the set of possible failures is bigger than one you can further nest this. If you have a decent pattern matching/switch implementation you can be informed of your failure to deal with a newly added error condition type.

I don't see the advantage of a discriminated union here (except for pattern matching, another nice feature many mainstream languages have failed to incorporate). Just as with a checked exception in Java's current implementation, a discriminated union pollutes method signatures up the call chain until the error has necessarily been handled or explicitly suppressed. The nice thing about exceptions is that they induce a discriminated union but unwind the stack until you can handle them so you don't need to "re-implement the either monad".

Quote:

I don't see why not. If the thing has changed sufficiently to merit new checked exceptions then there is likely to be far more pervasive changes that the compiler may not be helping you with. The onus is on someone to go and figure this all out. Hoping that the exceptions changing causes this is poor planning.

Just because the compiler can't flag everything doesn't mean it should flag nothing. Certainly changing the return type of an API call is significant enough to warrant looking carefully at the API's changes - should a compiler not flag such type mismatches?

Quote:

But this is not the same thing. There is no reasonable default behaviour for the addition of a new parameter where no default exists. the developer must decide what to do. There *is* a reasonable default behaviour in the vast majority of programming disciplines to a new *exceptional* circumstance. Die, with detail, if not dignity.

The reasonable default behavior of an unchecked exception is to propagate it, but IMO that isn't so with a checked exception.

Quote:

If you're doing something where deal with error conditions is so important then checked exceptions are utterly the wrong thing to be using. Way more powerful provably correct tools exist (albeit with much higher cost of implementing). why bother with a half assed solution that is trivial to circumvent.

Importance of error handling is orthogonal to whether business rules dictate that all errors of a certain type should be handled. But out of curiosity, what such tools do you know of?

Quote:

The key problem with checked exceptions is that the definition of 'must be dealt with' is defined at the exception level, rather than at the method level. At that stage I firmly believe that actually *not using exceptions* at that point is far, far better, albeit this works best when the language can enforce the check that all bases have been covered.

Yes, it's extremely silly that whether an exception is checked is based on its type. But that behavior isn't inherent to exception checking. It would be possible to be able to manually declare any exception as checked (opt-in), and have the compiler trace it up to any point at which it's manually marked as unchecked (can't deal with it anymore). Such a system would probably involve marking checked at the point of throwing and marking unchecked at the point of calling a method throwing a checked exception.

ML and Haskell aren't new. The point is that languages regressed substantially on type inference: we have a whole slew of new and popular languages and none of them holds a candle to ML or Haskell in type inference.

Taking this one separately as we are drifting OT.

Whilst it is true that for a while we regressed on type inference there were good reasons for it:

1) It is slow to do, releasing a new mainstream language with horribly slow compilation and intellisense in comparison to your peers loses you customers. I should note that, done from first principles it _vastly_ increases the complication of intellisense since it is desirable that this work on code which is partially 'broken'. The less hints there are about the type in question the harder you have to work, and the more speculative your guesses must be.2) Handling Overloading becomes vastly more complex. it's notable that f# tried to avoid the issue, then tried to get round it with annotations before finally including the capability automatically. It's hard to do but if you have overloading within the language you basically have to or it's a mess.3) if you get it wrong somewhere the compiler errors are hugely unhelpful, they have insufficient context to get you to a place where you can work back the offending line/type easily. Sometimes f#'s ones make we wish I was looking at a C++ template error.

Also some less good reasons (look at the number of people fervently decrying 'var' as being awful and a return to VB variant days[1])

As the performance of machines has gone up and more thought has gone into how to handle these things languages can afford to do more. Like I said, C# C++, java are all very mainstream and all have had inference of varying depth (some for a while).

Checked exceptions are not significantly hard to implement in a compiler, or IDE toolchain. It's the sort of thing you could use as an interview question. Performance considerations do not come into that.

Type inference is not a slam dunk win across the board either IMO.I personally would like _more_ type inference for c# especially for constructor calls (seemingly not that hard) and instance fields (actually quite hard) but I would never want the method signature parameters inferred, and I'm not actually that keen on how f# declares construction of new record instances (no name supplied, done on structural match).

1. Yes I know they're idiots, that's not the point, they exist and are a commercial consideration.

If you're a library you're assuming far too much on behalf of the callee.

If you're not (and so compiled in situ) then discriminated unions make far more sense as they force the caller to specifically deal with each call since then any significant changes to the semantics at all should result in the return type altering such that the compiler flags it, regardless of whether it's an exception case or not.

Exceptions were designed to be used in exceptional cases, loosely meaning "something went wrong", and allow the code to handle them to be separate from the code to handle the regular path. Why should any exceptional case have the default behavior to propagate the error? What if an API expects (but perhaps doesn't require) certain error handling code to be invoked if an error occurs? In that case you might still want to take advantage of the ability to separate your error handling code from your regular path code (without awkward manual code flow management).

Quote:

If you're a library you're assuming far too much on behalf of the callee.

If you're not (and so compiled in situ) then discriminated unions make far more sense as they force the caller to specifically deal with each call since then any significant changes to the semantics at all should result in the return type altering such that the compiler flags it, regardless of whether it's an exception case or not.

But checked exceptions work like discriminated unions, whether in a library or not, in that:* they induce a "discriminated union" in how the method returns: either it returns a value normally or returns abnormally via a checked exception (or something worse happens like it returns via an unchecked exception, but that's possible when using checked exceptions or discriminated unions);* the compiler forces you to explicitly deal with the possibility of an error.

Furthermore, exceptions sensibly unwind the stack until they can be handled; to get the same behavior with discriminated unions, you need to litter your code with "if error, return error" or lift it into an "either monad". Not that monadic programming is necessarily worse in general, but it's a pain in the ass in Java (simply encoding all your logic as function objects is a shit sandwich).

No, they don't. Type checking tells you when you actually commit an illegal operation, i.e., an actual error. If a type checking error occurs, you must fix your program in order for it to execute: you will be changing the actual execution logic of the code.

Java's checked exceptions tell you that you might have forgotten an exception, i.e., a warning (at best). If a checked exception "error" occurs, you may need to do no more than shut the compiler up: you do not necessarily have to change the actual execution logic of the code.

They're simply not comparable at all, and you cannot equivocate them. They're not even equiovocated in the language: type checking is enforced at runtime, while checked exception clauses are not.

Quote:

Nothing about passing the buck makes checking exceptions pointless.

Yes, it does, for the reason I stated above: we simply do not give a fuck about what exceptions could happen. We only care about what exceptions we must handle. Java checked exceptions do virtually nothing to help programmers achieve the latter: they function as an annoying documentation mechanism for the easiest part of the problem.

Quote:

Then the calling procedure must make that decision and the language must not force it either way. Java's implementation of checked exceptions typically forces the calling procedure to explicitly make that decision (of course you can find exceptions to that rule, such as if the same exception is thrown by multiple method calls).

So you agree that what Java does is bad for the overwhelmingly common case? Then why are you supporting it?

Quote:

Sure it can: it requires that there are arguments for all parameters, including callbacks (and, if you want to be pedantic, require that the relevant arguments are non-null, which can be done by making the type non-nullable and doing nullability tracing in the type system).

Sure, some hypothetical non-Java language could do that. Java cannot.

Quote:

That's ridiculous. If an IOException were to occur, that would indicate a programming bug, which can't reasonably be accounted for at a higher level, so why allow the checked exception to propagate? An AssertionError is more appropriate.

The problem is your assumption that an IOException might indicate a programming bug. That's simply not the case, even in your example. That's why I put "knowing" in quotes about your original claim: the odds that any given client programmer knows every last reason a given exception might be thrown are pretty small, especially for the higher-level, broad based exceptions like IOException, SQLException, etc. Heck, I don't even have high confident that the class authors know all the cases!

Plus, it's simply silly: if the exception can "never happen", then there should be no exception handler in the calling code. Therefore, wrapping the exception in AssertionError just lets us avoid writing the 'throws clause'. If you hate them so much, why are you so adamantly supporting them? The whole of your argument is not the least bit consistent.

As for declaring it and letting it happen, yes you can do that and modern IDEs are very good at letting you do so the entire way up the call stack, but just because you can doesn't mean you should and it's horribly invasive.

The entire feature is horribly invasive, so that ship has already sailed. Wrapping checked exceptions in RuntimeExceptions to avoid the mechanism is unquestionable worse, because:

It makes writing exception handlers harder, since you have to be careful about nesting.

It makes stack traces uglier

'throws Exception' is minimally invasive and doesn't have these drawbacks.

Quote:

If you know the situation is irrecoverable, don't make the higher level stuff care about your low level bug.

As I explained in my last response to LH, exception checking reconciles what could actually happen with what the programmer thinks could happen. That alone verifies the programmer's reasoning, increasing correctness.

But not in any helpful way. I have never, ever written code where I've thought, "I know I need an exception handler here but I have no clue what exception(s) I must catch." Even if I ever encountered that situation, a quick visit to the documentation would clear that right up.

The questions I do wrestle with are, "Do I need to handle this exception?" and "Where should I best handle this exception?" and "What do I do when handling this exception?" Checked exception clauses do nothing to help me answer these questions.

Plainly, I wouldn't trust anyone who relies on checked exceptions to get their code right to be capable of writing whatever application logic I'm paying them to write.

Quote:

You're assuming that you always have to declare checked exceptions. My first post in this thread suggests that the compiler traces them through the flow of the code and only generates an error if the programmer adds an incorrect "throws" clause, avoiding the boilerplate.

Yes, but Java doesn't do this and never will, so this is a distraction at absolute best. In reality, it's just putting lipstick on two pigs.

Quote:

Throwing a new exception always changes specification, whether checked or not, so either way it has the same effect on encapsulation.

Actually it doesn't, because of Java's language rules. You may get a Throwable at any point in execution[1]. Which is the whole problem: checked exceptions (in Java) aren't actually telling us what exceptions might be thrown, but rather, here's the subset of exceptions that could be thrown that you might care about. Only it's a pretty poor solution for that issue.

[1] Moreover, you're going to be pretty hard pressed to create any managed language without this property. You'd have to give up garbage collection, lazy code/class loading, and tons of other stuff.

But perhaps it's because I use checked exceptions to their strengths and not to their weaknesses: I only make an exception checked if it implies a situation that requires accounting for, which is uncommon, and I otherwise avoid them (except as libraries require, usually incorrectly so).

Again, your ability to do this as the class author is essentially non-existent. Few errors are that clean, and almost all of them are programming bugs (i.e., they should be fatal)! Moreover, the inability to distinguish "errors we can handle" from "fatal-ish errors" goes all the way down to the metal. As such, I flatly don't believe you. You may think you've done this, but you probably actually haven't.

Quote:

Sorry for being unclear. But keep in mind that I never said checked exceptions in their current implementation or my suggested implementation are good

Merely arguing for them even in part (which you have done) necessarily implies they're a good thing. Moreover, you've seriously argued for them as a benefit multiple times in the past, and there's zero reason to believe you've changed your tune now. Plus, even if you were playing devil's advocate, this was not the place to do it, especially from the start.

Quote:

As an aside, when would exceptions be checked if not at compile time?

At runtime, just like C++ does?

Quote:

It's unreasonable to expect programmers to "reason by diff" on a large project.

It's equally unreasonable for the programming language to force me to declare I want the default behavior everywhere.

The reasonable default behavior of an unchecked exception is to propagate it, but IMO that isn't so with a checked exception.

It's true for every last checked exception in the Java API. If you believe this, then you can provide rationalize for all (heck, most) of them. This is whole the problem with your current line of reasoning: even if I agreed that checked exceptions are a good thing for exceptions that must be handled (or even handled in 95% of all applications), I don't believe you actually can name those exceptions. Java completely and utterly failed at that task. I suspect you'd be hard pressed to find even one exception in the standard API where that's the case.

Quote:

Importance of error handling is orthogonal to whether business rules dictate that all errors of a certain type should be handled.

No, it isn't. How can it be, unless you think all business rules lack any rational basis.

Quote:

But that behavior isn't inherent to exception checking. It would be possible to be able to manually declare any exception as checked (opt-in), and have the compiler trace it up to any point at which it's manually marked as unchecked (can't deal with it anymore). Such a system would probably involve marking checked at the point of throwing and marking unchecked at the point of calling a method throwing a checked exception.

This doesn't get you a damn thing, both theoretically and in the implementation you described.

Exceptions were designed to be used in exceptional cases, loosely meaning "something went wrong", and allow the code to handle them to be separate from the code to handle the regular path. Why should any exceptional case have the default behavior to propagate the error?

Because the normal code path cannot continue forward! As such, you have to go some retry point. If there are no retry points, you must exit. Anything else is inviting undefined behavior. Such a mechanism need not propagate via stack unwinding, but it has to propagate the error somewhere.

No, they don't. Type checking tells you when you actually commit an illegal operation, i.e., an actual error. If a type checking error occurs, you must fix your program in order for it to execute: you will be changing the actual execution logic of the code.

Java's checked exceptions tell you that you might have forgotten an exception, i.e., a warning (at best). If a checked exception "error" occurs, you may need to do no more than shut the compiler up: you do not necessarily have to change the actual execution logic of the code.

They're simply not comparable at all, and you cannot equivocate them. They're not even equiovocated in the language: type checking is enforced at runtime, while checked exception clauses are not.

Java and all similar programming languages are unnecessarily conservative in many ways: things that, according to you, should be warnings are errors. Assigning an object of compile-time class X to a variable with a compile-time class a subclass of X is an example: it may be correct but the compiler gives an error. The programmer must manually tell the compiler that this potentially unsafe operation is safe. Should that be a warning instead? If not, why not treat checked exceptions the same way, so that by default the compiler requires an exception to explicitly be caught or allowed to propogate but marking it as not given a shit about causes the compiler to treat it as unchecked from that point up?

Quote:

Yes, it does, for the reason I stated above: we simply do not give a fuck about what exceptions could happen. We only care about what exceptions we must handle. Java checked exceptions do virtually nothing to help programmers achieve the latter: they function as an annoying documentation mechanism for the easiest part of the problem.

Checked exceptions are supposed to approximate the exceptions we must handle. In general a method doesn't know what types of erorrs its callers are interested in. But in certain cases, a method can be fairly confident that certain errors must be handled, especially when the method is internal to a program and not an externally facing API, in which case both the method and its callers face the same business rules.

For example, in an app I wrote, certain user actions would involve calling a small number of methods to contact remote servers. These actions could reasonably fail and necessitated call-site-specific operations, such as queueing the operation for retry later or to notifying the user. The easiest way to avoid forgetting to handle an error was to make it a checked exception.

Quote:

So you agree that what Java does is bad for the overwhelmingly common case? Then why are you supporting it?

I'm not supporting Java's checked exceptions; nor do I advocate them in the overwhelmingly common case. I use them sparingly and consider them awkward even when they work.

Quote:

Sure, some hypothetical non-Java language could do that. Java cannot.

Great. I'm glad we agree that Java is a suboptimal language.

Quote:

The problem is your assumption that an IOException might indicate a programming bug. That's simply not the case, even in your example.

How so? If doSomethingWithAStream documents that it throws an IOException only due to reading the stream passed in, an IOException indicates that the stream threw an IOException or doSomethingWithAStream has a bug. A ByteArrayInputStream doesn't throw an IOException so if an IOException is thrown, there must be a bug somewhere.

Quote:

That's why I put "knowing" in quotes about your original claim: the odds that any given client programmer knows every last reason a given exception might be thrown are pretty small, especially for the higher-level, broad based exceptions like IOException, SQLException, etc. Heck, I don't even have high confident that the class authors know all the cases!

That's why it's ridiculous to tie the "checkedness" of the exception to its class.

Quote:

Plus, it's simply silly: if the exception can "never happen", then there should be no exception handler in the calling code. Therefore, wrapping the exception in AssertionError just lets us avoid writing the 'throws clause'. If you hate them so much, why are you so adamantly supporting them? The whole of your argument is not the least bit consistent.

If an exception can "never happen", the language still trips me up. It pollutes the method's declared API and that pollution spreads unless it's manually suppressed. I'm not adamantly supporting how Java treats checked exceptions—I'm not even supporting them in general.

--

LordHunter317 wrote:

But not in any helpful way. I have never, ever written code where I've thought, "I know I need an exception handler here but I have no clue what exception(s) I must catch." Even if I ever encountered that situation, a quick visit to the documentation would clear that right up.

The questions I do wrestle with are, "Do I need to handle this exception?" and "Where should I best handle this exception?" and "What do I do when handling this exception?" Checked exception clauses do nothing to help me answer these questions.

Plainly, I wouldn't trust anyone who relies on checked exceptions to get their code right to be capable of writing whatever application logic I'm paying them to write.

So it's useless to assert "these errors have been dealt with by this point"? Code flow is difficult to analyze in a large program, especially as the code changes over time. I think there's value in automating the process of checking that certain errors have been dealt with, especially if there are layers of middleware between where errors are generated and where they're handled.

Quote:

Yes, but Java doesn't do this and never will, so this is a distraction at absolute best. In reality, it's just putting lipstick on two pigs.

It's eliminating the pig entirely. It'd be entirely opt-in.

Quote:

Actually it doesn't, because of Java's language rules. You may get a Throwable at any point in execution[1].[1] Moreover, you're going to be pretty hard pressed to create any managed language without this property. You'd have to give up garbage collection, lazy code/class loading, and tons of other stuff.

Only due to especially pernicious coding. Lazy class initialization can cause ExceptionInInitializerErrors, NoClassDefFoundErrors, LinkageErrors, and a variety of other unchecked exceptions; similarly for garbage collection. I don't see how that's relevant to checked exceptions.

--

LordHunter317 wrote:

Again, your ability to do this as the class author is essentially non-existent. Few errors are that clean, and almost all of them are programming bugs (i.e., they should be fatal)! Moreover, the inability to distinguish "errors we can handle" from "fatal-ish errors" goes all the way down to the metal. As such, I flatly don't believe you. You may think you've done this, but you probably actually haven't.

I have written applications that have business rules to account for various types of failure: "if remote service x isn't available, if using it in y part of the application, do z; if using it in a part of the application, do b; etc." So I'm pretty confident that these errors must be handled.

Quote:

Merely arguing for them even in part (which you have done) necessarily implies they're a good thing. Moreover, you've seriously argued for them as a benefit multiple times in the past, and there's zero reason to believe you've changed your tune now. Plus, even if you were playing devil's advocate, this was not the place to do it, especially from the start.

Wow, really??? There's no place for nuance in your world? No value in thinking that checked exceptions in their current implementation are deeply flawed but here are a couple ideas that may redeem them and I'd like to hear feedback on them?

Quote:

At runtime, just like C++ does?

Those aren't checked exceptions.

Quote:

It's equally unreasonable for the programming language to force me to declare I want the default behavior everywhere.

I don't especially like that aspect of checked exceptions; nor should checked exceptions be used where propagation is the default behavior.

If the two are doing the same thing, how is that an advantage for discriminated unions? I gave a concrete advantage of exceptions—the option of stack unwinding. Discriminated unions need a corresponding advantage to be worth using in general.

Quote:

It's true for every last checked exception in the Java API. If you believe this, then you can provide rationalize for all (heck, most) of them. This is whole the problem with your current line of reasoning: even if I agreed that checked exceptions are a good thing for exceptions that must be handled (or even handled in 95% of all applications), I don't believe you actually can name those exceptions. Java completely and utterly failed at that task. I suspect you'd be hard pressed to find even one exception in the standard API where that's the case.

I don't support IOException, SQLException, InterruptedException, InvocationTargetException, etc. being checked. They're just nuissances. In fact, there are few situations where checked exceptions are appropriate, and a standard library that must be as general as possible runs counter to the idea that you know what the caller must handle. So the standard library's use of checked exceptions is flawed.

Quote:

No, it isn't. How can it be, unless you think all business rules lack any rational basis.

I was wrong—there is some correlation between the two—but they are not the same.

Quote:

This doesn't get you a damn thing, both theoretically and in the implementation you described.

Sure it does: it separates two separate concerns: the cause of error and whether it must be handled. It also allows opting into unchecked propagation of errors without boilerplate.

--

LordHunter317 wrote:

Because the normal code path cannot continue forward! As such, you have to go some retry point. If there are no retry points, you must exit. Anything else is inviting undefined behavior. Such a mechanism need not propagate via stack unwinding, but it has to propagate the error somewhere.

But you're assuming the calling code is fixed. If it isn't, if it hasn't even been written yet, it isn't at all clear that the default behavior should be to propagate.

Java and all similar programming languages are unnecessarily conservative in many ways: things that, according to you, should be warnings are errors. Assigning an object of compile-time class X to a variable with a compile-time class a subclass of X is an example: it may be correct but the compiler gives an error.

(emphasis mine). Without the cast, the code as written is incorrect. Moreover, adding the cast actually changes the generated code, it is not merely a directive to shut up the typer! In some languages, like C++[1], you must even ask for it explicitly vs. other conversion operations, and it changes the generated code substantially.

Quote:

If not, why not treat checked exceptions the same way, so that by default the compiler requires an exception to explicitly be caught or allowed to propogate but marking it as not given a shit about causes the compiler to treat it as unchecked from that point up?

Because from a language perspective, upwards propagation all the way to the top is both:

The default behavior

A correct behavior.

Moreover, it's the correct behavior for most exceptions. Warnings are useless if they're wrong more often then they're right.

Even for the very rare (unicorn!) exceptions where you want this, it's not really enough to achieve your actual goal. You need a lot of machinery to be able to say "I do/don't care about these exceptions being raised" both in terms of language syntax and typing support. Even then, you still haven't verified what you ultimately care about: that the exception was actually handled at some point. To do that, you need whole program analysis (which is pretty incompatible with the JVM) and you have to give up some usage of some features, like reflection. Achieving what you actual want is costly, expensive, and complicated. This is why it's done by an entirely separate tool for O'Caml.

Quote:

Checked exceptions are supposed to approximate the exceptions we must handle. But in certain cases, a method can be fairly confident that certain errors must be handled, especially when the method is internal to a program and not an externally facing API, in which case both the method and its callers face the same business rules

Sure, but no one has managed to actually achieve this generally. Java is a complete failure. You haven't managed to even present any concrete examples w/ actual code. When I asked you to do so, you agreed with me that Java got it wrong but still didn't give an example. You're going to have to get explicit to support your argument, with code and everything, for me to believe the feature is even solving a real problem. I don't believe it is, outside of very contrived situations.

Quote:

For example, in an app I wrote, certain user actions would involve calling a small number of methods to contact remote servers. These actions could reasonably fail and necessitated call-site-specific operations, such as queueing the operation for retry later or to notifying the user. The easiest way to avoid forgetting to handle an error was to make it a checked exception.

Not true, since checked exceptions don't make you write the necessary catch clauses, or even verify that they exist. Secondly, most (all?) of your the causative exceptions were "low-level" exceptions like I/O errors, DNS errors, and the like, which would not be checked in your hypothetical language. To ensure they're all handled, you have to do one of two things:

Switch on exception checking for all exceptions, which carries all of the problems I list above, plus some additional ones.

Nest the causative errors inside a checked exception you created, which is prone to error whenever they change or if the underlying specification is incomplete. Even if you get it right, it's still very, very brittle.

Quote:

How so? If doSomethingWithAStream documents that it throws an IOException only due to reading the stream passed in, an IOException indicates that the stream threw an IOException or doSomethingWithAStream has a bug. A ByteArrayInputStream doesn't throw an IOException so if an IOException is thrown, there must be a bug somewhere.

Which possibilties are more likely:

The writer of doSomethingWithAStream wrote code that explicitly throws IOException and lied about it?

The writer of doSomethingWithAStream falsely claimed that his code would never throw an IOException unless the passed stream does, and then went and wrote code that actually can throw IOException in other cases?

You read the docs wrong

Yes, if the documentation is actually true and states that, then it should not happen in the exact situation you created. However, even you yourself indicated the odds of that being true: "This way you don't have to wrongly state that an exception will be thrown - instead, you wrap the exception in an unchecked error that will make it obvious if for some bizarre reason an IOException occurs. (It could occur due to your failure to read the documentation of doSomethingWithAStream.)" (emphasis mine).

But the code is still bad even in that case, because it's fantastically brittle:

ByteArrayInputStream doesn't actually promise it will not throw IOException. It only promises you can continue to use it after calling close()[2]

There are tons of trivial changes to doSomethingWithInputStream() that could invalidate its documentation. Wrapping the passed stream in an BufferedInputStream would be enough.

Changing the passed stream type breaks the code.

Like I said, the assumptions required to support "this exception can never happen" are pretty difficult to make generally, especially for broad-based exceptions. Even when you can do so, it doesn't seem to get you anything whatsoever.

Quote:

So it's useless to assert "these errors have been dealt with by this point"?

Sure, that might be a useful thing to assert in some cases, but checked exceptions don't do that. They do the exact opposite: they indicate that the error has not been dealt with yet. That's not enough information to get to what you want, generally. Doing what you want requires a requires a lot more work.

Quote:

Only due to especially pernicious coding. Lazy class initialization can cause ExceptionInInitializerErrors, NoClassDefFoundErrors, LinkageErrors, and a variety of other unchecked exceptions; similarly for garbage collection. I don't see how that's relevant to checked exceptions.

It's completely relevant to whether adding exceptions to the throws clause is an encapsulation change or not. I would generally argue "not really" since all methods are effectively 'throws Throwable' in the first place. ShuggyCoUk's original argument was (AFAICT) that checked exceptions create encapsulation problems because they allow implementation details to "leak", e.g., my library can fail because of an I/O error or a SQL error. Your argument, AFAICT, is that changing the code to throw a new exception is an API change, thus the net result is the same.

While true, I'm pointing out all of that's rather irrelevant since callers need to be notionally prepared for any exception to be thrown at anytime, or something very close to that. Hence catch-all blocks and finally. Besides, merely throwing an new type of exception doesn't necessary require any changes to clients, versus changes like adding a parameter to a method or changing a return type.

Aside: They're also not normally encapsulation problems. Meaningfully handling an error requires knowing what actually happened. Hence, those low-level problems are rarely implementation details even if we desperately wish to pretend otherwise.

Quote:

Quote:

Again, your ability to do this as the class author is essentially non-existent. Few errors are that clean, and almost all of them are programming bugs (i.e., they should be fatal)! Moreover, the inability to distinguish "errors we can handle" from "fatal-ish errors" goes all the way down to the metal. As such, I flatly don't believe you. You may think you've done this, but you probably actually haven't.

I have written applications that have business rules to account for various types of failure: "if remote service x isn't available, if using it in y part of the application, do z; if using it in a part of the application, do b; etc." So I'm pretty confident that these errors must be handled.

So have I. Arguments of the form "the class author is also the class user" aren't particularly interesting in the first place. Even if they were, this is still insufficient as an argument for the usage or even existence of checked exceptions. Like I said, figuring out "what exceptions could be thrown" should never be a problem. I don't need the damn programming language to remind me.

Quote:

Quote:

At runtime, just like C++ does?

Those aren't checked exceptions.

They're close enough for the purposes of this discussion. But it's irrelevant, as you asked when else you would enforce checked exceptions, and at runtime is the obvious answer. Checking exception specification certainly can be done at runtime, and would have to be done at runtime in certain situations (e.g., when reflection is involved).

If the two are doing the same thing, how is that an advantage for discriminated unions?

Ok, I said that poorly. Checked exceptions basically don't do that at all, while the variant absolutely does that. It forces you to handle the exception, as it is no longer optional.

Quote:

Quote:

This doesn't get you a damn thing, both theoretically and in the implementation you described.

Sure it does: it separates two separate concerns: the cause of error and whether it must be handled. It also allows opting into unchecked propagation of errors without boilerplate.

That is not at all what you described. As best as I can tell, what you describe would never check an exception since they'd be unchecked all of the time!

Quote:

But you're assuming the calling code is fixed. If it isn't, if it hasn't even been written yet, it isn't at all clear that the default behavior should be to propagate.

Huh? The propagation happens at runtime, hence the code must exist. What else can a language possibly do, besides halt on the spot of error? The default behavior isn't an arbitrary default, but truly because there is no other recourse.

[1] At least in some cases. This is an unfortunate oversight.[2] This too is an unfortunate oversight and an LSP violation.

I'm not supporting Java's checked exceptions; nor do I advocate them in the overwhelmingly common case. I use them sparingly and consider them awkward even when they work.

This contradicts your opening post, and your claimed usage of them to benefit you!

Quote:

Wow, really??? There's no place for nuance in your world? No value in thinking that checked exceptions in their current implementation are deeply flawed but here are a couple ideas that may redeem them and I'd like to hear feedback on them?

There's plenty of room for nuance, but you really haven't taken a nuanced position. What you've taken is an inconsistent position, which is entirely different. You state that you don't support what Java does, but then talk about how it is advantageous. Not just theoretically, but for applications you've actually written. As such, I'm making a conscious decision to reject when you say, "I don't support Java's checked exceptions", because your statements are more consistent that way.

Moreover, even if your intent from the beginning was to talk about "what checked exceptions could have been", I was noting this really wasn't the thread to do it in, especially from the start. Not that it matters in the least now, or even when I said it.

(emphasis mine). Without the cast, the code as written is incorrect. Moreover, adding the cast actually changes the generated code, it is not merely a directive to shut up the typer! In some languages, like C++[1], you must even ask for it explicitly vs. other conversion operations, and it changes the generated code substantially.

A cast on assignment could be done automatically: it's only incorrect because it's defined as incorrect. But it would be silly to do that because it would greatly increase the possibility of error.

Quote:

Because from a language perspective, upwards propagation all the way to the top is both:

The default behavior

A correct behavior.

Moreover, it's the correct behavior for most exceptions. Warnings are useless if they're wrong more often then they're right.

If you have to opt into marking exceptions as checked, it isn't at all clear that propagation is the correct behavior for checked exceptions. You'd only mark an exception as checked if there is no reasonable default behavior and you want the caller to think about the exception.

Quote:

Even for the very rare (unicorn!) exceptions where you want this, it's not really enough to achieve your actual goal. You need a lot of machinery to be able to say "I do/don't care about these exceptions being raised" both in terms of language syntax and typing support. Even then, you still haven't verified what you ultimately care about: that the exception was actually handled at some point. To do that, you need whole program analysis (which is pretty incompatible with the JVM) and you have to give up some usage of some features, like reflection. Achieving what you actual want is costly, expensive, and complicated. This is why it's done by an entirely separate tool for O'Caml.

All you need is a simple syntax for marking an exception as checked upon throwing it, say "throw checked", a simple syntax for explicitly unchecking a checked exception, a list of checked exceptions in each compiled method, and a compile-time check that if a method specifies a "throws" clause, only those checked exceptions can propagate out of it (needless to say, we can ignore the usual pathologies). I suppose there would be problems if you recompile a class without recompiling classes using that class, but the same problems exist if you change the class in other incompatable ways.

Reflection wraps exceptions anyways so unknown checked exceptions don't leak through reflection calls. (Although wrapping exceptions to a large degree destroys exception handling. Reflection is incompatible with compile-time checking of exceptions, although a safe subset could be checked at compile-time, but that's off topic.)

Quote:

Sure, but no one has managed to actually achieve this generally. Java is a complete failure. You haven't managed to even present any concrete examples w/ actual code. When I asked you to do so, you agreed with me that Java got it wrong but still didn't give an example. You're going to have to get explicit to support your argument, with code and everything, for me to believe the feature is even solving a real problem. I don't believe it is, outside of very contrived situations.

I provided a reasonable and concrete example; don't shift the goalposts and put an unreasonable burden on me. Obviously I'm unable to post actual business code here and I'm not going to rewrite a substantial part of it here.

Quote:

Not true, since checked exceptions don't make you write the necessary catch clauses, or even verify that they exist.

They force me to acknowledge the exceptions, which greatly reduces the chance that I'd erroniously omit a catch clause. And since the top call site is essentially a Runnable, I do eventually need to catch all checked exceptions.

Quote:

Secondly, most (all?) of your the causative exceptions were "low-level" exceptions like I/O errors, DNS errors, and the like, which would not be checked in your hypothetical language. To ensure they're all handled, you have to do one of two things:

Switch on exception checking for all exceptions, which carries all of the problems I list above, plus some additional ones.

Nest the causative errors inside a checked exception you created, which is prone to error whenever they change or if the underlying specification is incomplete. Even if you get it right, it's still very, very brittle.

On I/O failure the remote connecting methods throw a specific exception to indicate failure to communicate. That exception is caught higher up. There's nothing complex about it and I'd imagine most GUI apps that connect remotely have similar requirements and thus would benefit from a similar pattern.

Quote:

Which possibilties are more likely:

The writer of doSomethingWithAStream wrote code that explicitly throws IOException and lied about it?

The writer of doSomethingWithAStream falsely claimed that his code would never throw an IOException unless the passed stream does, and then went and wrote code that actually can throw IOException in other cases?

You read the docs wrong

Yes, if the documentation is actually true and states that, then it should not happen in the exact situation you created. However, even you yourself indicated the odds of that being true: "This way you don't have to wrongly state that an exception will be thrown - instead, you wrap the exception in an unchecked error that will make it obvious if for some bizarre reason an IOException occurs. (It could occur due to your failure to read the documentation of doSomethingWithAStream.)" (emphasis mine).

But the code is still bad even in that case, because it's fantastically brittle:

ByteArrayInputStream doesn't actually promise it will not throw IOException. It only promises you can continue to use it after calling close()[2]

There are tons of trivial changes to doSomethingWithInputStream() that could invalidate its documentation. Wrapping the passed stream in an BufferedInputStream would be enough.

Changing the passed stream type breaks the code.

Like I said, the assumptions required to support "this exception can never happen" are pretty difficult to make generally, especially for broad-based exceptions. Even when you can do so, it doesn't seem to get you anything whatsoever.

The only methods of ByteArrayInputStream that have "throws IOException" are close(), which states that it has no effect, and read(byte[]) on the super class, whose documentation states that it's equivalent to read(byte[], int, int), which doesn't throw an IOException.

Changing the passed-in stream's implementation does break the code, but expecting otherwise is unreasonable. When you change code, you must at least make the slightest effort to consider the impact on immediately surrounding code. And if you do make this mistake, it will be caught at runtime.

Quote:

Sure, that might be a useful thing to assert in some cases, but checked exceptions don't do that. They do the exact opposite: they indicate that the error has not been dealt with yet. That's not enough information to get to what you want, generally. Doing what you want requires a requires a lot more work.

Checked exceptions could do that, and with little difficulty in use or implementation.

Quote:

It's completely relevant to whether adding exceptions to the throws clause is an encapsulation change or not. I would generally argue "not really" since all methods are effectively 'throws Throwable' in the first place.

Only in the most severe cases of incompetence would methods throw undeclared checked exceptions. I mean, you might as well say that none of Java's rules really apply because you can do anything with the Unsafe class. But those would take criminal incompetence and so such an argument is disingenuous.

Quote:

ShuggyCoUk's original argument was (AFAICT) that checked exceptions create encapsulation problems because they allow implementation details to "leak", e.g., my library can fail because of an I/O error or a SQL error. Your argument, AFAICT, is that changing the code to throw a new exception is an API change, thus the net result is the same.

While true, I'm pointing out all of that's rather irrelevant since callers need to be notionally prepared for any exception to be thrown at anytime, or something very close to that. Hence catch-all blocks and finally. Besides, merely throwing an new type of exception doesn't necessary require any changes to clients, versus changes like adding a parameter to a method or changing a return type.

Aside: They're also not normally encapsulation problems. Meaningfully handling an error requires knowing what actually happened. Hence, those low-level problems are rarely implementation details even if we desperately wish to pretend otherwise.

Certain types of exception can happen nearly anywhere but they tend to be Errors that can't reasonably be handled in a vast majority of cases. "Normal" exceptions, on the other hand, don't happen out of the blue. Yes, there are exceptions that are sufficiently common that they can happen nearly anywhere, and also indicate programming bugs and thus are rare to catch, such as NPEs, Illegal(Argument|State)Exceptions, etc. and thus adding one of those doesn't meaningfully change specification, but again we aren't speaking in general. Changing a method so that it now does IO, and thus we have to deal with a new type of exception that one reasonably could care about and that doesn't indicate a bug, is a meaningful API change whether or not IO exceptions happen to be checked. If a method goes from not requiring an internet connection to requiring one, that's a pretty damned important change to know about and brings in a whole bunch of potential issues.

Quote:

So have I. Arguments of the form "the class author is also the class user" aren't particularly interesting in the first place. Even if they were, this is still insufficient as an argument for the usage or even existence of checked exceptions. Like I said, figuring out "what exceptions could be thrown" should never be a problem. I don't need the damn programming language to remind me.

Great, maybe you're a better programmer than I am. I would like all the help I can get. My unit tests routinely turn up bugs. I'd be thankful for anything the compiler can do to find those earlier without harrassing me.

Quote:

They're close enough for the purposes of this discussion. But it's irrelevant, as you asked when else you would enforce checked exceptions, and at runtime is the obvious answer. Checking exception specification certainly can be done at runtime, and would have to be done at runtime in certain situations (e.g., when reflection is involved).

I thought it was clear from context that we were talking about exceptions that were statically checked. Otherwise, you might as well call all exceptions checked.

Quote:

Ok, I said that poorly. Checked exceptions basically don't do that at all, while the variant absolutely does that. It forces you to handle the exception, as it is no longer optional.

Checked exceptions only don't force you to acknowledge them if there are multiple sources of the same type of exception, and typically as those sources have the same sort of cause, you want to handle them the same way. While you can just rethrow a checked exception, doing so is opt-in, and you can assume the variety of the discriminated union without a proper check.

Quote:

That is not at all what you described. As best as I can tell, what you describe would never check an exception since they'd be unchecked all of the time!

It would only never check an exception if you never mark an exception as checked.

Quote:

Huh? The propagation happens at runtime, hence the code must exist. What else can a language possibly do, besides halt on the spot of error? The default behavior isn't an arbitrary default, but truly because there is no other recourse.

I don't think you understand what I meant. If the runtime is given some code in which an exception occurs and told to evaluate it, and the code has no exception handling, propagation is the perfectly reasonable response to the exception. The code is given and there's basically nothing else to do. But why should the language always allow you to write code relying on that default? Why should the language not ever require you to decide which behavior you want?

Put another way, the fact that a situation is exceptional doesn't inherently imply an error handling strategy. Most exceptional situations are best handled in a certain way, but that doesn't preclude a non-negligible and easily identified subset that are best handled in another way. If such a subset exists, why should the language not allow identifying it to opt out of the default exception handling behavior?

--

LordHunter317 wrote:

This contradicts your opening post, and your claimed usage of them to benefit you!

??? My opening post in no way endorses Java's checked exceptions. It endorses an abstract idea behind them but never says that that idea can be achieved in a net beneficial way.

Quote:

There's plenty of room for nuance, but you really haven't taken a nuanced position. What you've taken is an inconsistent position, which is entirely different. You state that you don't support what Java does, but then talk about how it is advantageous. Not just theoretically, but for applications you've actually written. As such, I'm making a conscious decision to reject when you say, "I don't support Java's checked exceptions", because your statements are more consistent that way.

I've cited certain cases where I've benefited from checked exceptions. But there are numerous cases where they hound me and I've described a number of serious problems with them. I don't know why you're honing in on a few things I said and not others.

Quote:

Moreover, even if your intent from the beginning was to talk about "what checked exceptions could have been", I was noting this really wasn't the thread to do it in, especially from the start. Not that it matters in the least now, or even when I said it.

The original problem was fixed and Shuggy provided followup reading. At that point I figured the main questions were answered. At that point I see no problem with a discussion of the topic at hand, but maybe it should have been in another thread.

All you need is a simple syntax for marking an exception as checked upon throwing it, say "throw checked", a simple syntax for explicitly unchecking a checked exception, a list of checked exceptions in each compiled method, and a compile-time check that if a method specifies a "throws" clause, only those checked exceptions can propagate out of it (needless to say, we can ignore the usual pathologies).

Nope, that's not enough. How does that enforce I handled (read: wrote a catch block) every checked exception? It does not. It doesn't improve on the current situation one damn bit.

Quote:

I provided a reasonable and concrete example;

Your "example" is nothing of the sort, and it applies to every application on the planet that talks to a remote server. You could be talking about wget(1) or curl(1) for all I know. You probably couldn't get more generic even if you tried[1]. Regardless, "My business rules say I have to handle these exceptions" doesn't justify checked exceptions, because checked exceptions do not ensure you handle them! I'm not sure why such elementary logic is beyond you.

Quote:

Obviously I'm unable to post actual business code here and I'm not going to rewrite a substantial part of it here.

If you can't extract the gist of it, or make up an actual meaningful example, then I don't believe you've done what you claimed. Plus, there's the whole bit that you've claiming you've managed to accomplish something essentially no one else has done. Extraordinary claims require extraordinary proof and all that.

I flat out don't believe for a second you've created a series of exception classes that must be handled by all callers, no matter what. I don't believe you've even created a single exception class where that's the case. The fact that your business logic requires to be handled right now isn't enough. Business logic can change and that includes the error handling responses, and even what errors will be handled. At best, you've created a case where it's true because you have one client, so you can strongly couple between the class user and the class itself. Which is obviously not the least bit compelling.

Quote:

They force me to acknowledge the exceptions, which greatly reduces the chance that I'd erroniously omit a catch clause.

Here's the problem with that argument: there's legions and legions of Java code that gets exception handling wrong, including not handling exceptions when they should. Likewise, there's legions of C++, Python, and C# code that gets it right without checked exceptions. As such, I can look at the volume of code out there and pretty readily and safely draw the conclusion that exception clauses are not needed for programmers to correctly determine which exceptions to handle. You're not really going to be able to create a compelling argument along this line.

Quote:

On I/O failure the remote connecting methods throw a specific exception to indicate failure to communicate. That exception is caught higher up. There's nothing complex about it and I'd imagine most GUI apps that connect remotely have similar requirements and thus would benefit from a similar pattern.

Yes and? My entire point is what if the exceptions that indicate I/O failure change? What do you do then to ensure you definitely responded to them? The language doesn't help you with that one iota. Nothing you've proposed helps with that one iota.

:confused: The second case was explicitly a documentation error! I'm flat out saying that what doSomethingWithAStream() claims it does, and what it actually does are different. There's plenty of ways to nest streams such that an IOException even though it's a ByteArrayInputStream at the bottom.

Which is my entire point: the assumptions required to do what you suggested are both dubious and brittle. You're enforcing very stringent requirements on the code you call, that aren't in keeping with the Java I/O library in spirit or practice.

Quote:

The only methods of ByteArrayInputStream that have "throws IOException" are close(), which states that it has no effect, and read(byte[]) on the super class, whose documentation states that it's equivalent to read(byte[], int, int), which doesn't throw an IOException.

Sure, that might be a useful thing to assert in some cases, but checked exceptions don't do that. They do the exact opposite: they indicate that the error has not been dealt with yet. That's not enough information to get to what you want, generally. Doing what you want requires a requires a lot more work.

Checked exceptions could do that, and with little difficulty in use or implementation.

No, they can never do that. There is no general way to infer what has been handled based on simply knowing what hasn't been handled, or even what hasn't been handled plus what is thrown. You actually have to walk the entire program path and look for the catch blocks and make sure they are where you want them to be. It absolutely requires static flow analysis of the whole application.

The throws clause doesn't tell you whether that happened. Even the throws clause plus all the throw statements doesn't tell you. You must walk the program, statement by statement, and see what happens.

Quote:

Only in the most severe cases of incompetence would methods throw undeclared checked exceptions.

You're missing the point: code correctness overwhelmingly depends writing code that will safely execute in the presence of any thrown exception, unless responding to a specific exception (i.e., writing a catch block). Most code is absolutely written based on the notion of 'throws Throwable', more importantly, it must be written that way.

Quote:

Great, maybe you're a better programmer than I am. I would like all the help I can get.

All the help you need here is to read and comprehend the documentation. Literally, that's all checked exceptions are saving you from doing. Except they don't, because you need to read the documentation to learn other things before you call the damn method in the first place!

Quote:

My unit tests routinely turn up bugs.

I would be pretty shocked if any of those bugs were ever "I meant to catch X but instead caught Y". If that's happening routinely, then I fully stand by what I've already said.

Quote:

I don't think you understand what I meant. If the runtime is given some code in which an exception occurs and told to evaluate it, and the code has no exception handling, propagation is the perfectly reasonable response to the exception. The code is given and there's basically nothing else to do. But why should the language always allow you to write code relying on that default? Why should the language not ever require you to decide which behavior you want?

Because there are literally no alternatives beyond forcing you to write a handler for every last exception or dying on the spot.

Quote:

If such a subset exists, why should the language not allow identifying it to opt out of the default exception handling behavior?

Going to the exception handler is propagation, whether it happens via stack unwinding or not.

Quote:

??? My opening post in no way endorses Java's checked exceptions. It endorses an abstract idea behind them but never says that that idea can be achieved in a net beneficial way.

(emphasis mine). It's virtually impossible to endorse the notion but not the implementation, especially when you continually and confusingly conflate the two!

Quote:

I've cited certain cases where I've benefited from checked exceptions. But there are numerous cases where they hound me and I've described a number of serious problems with them. I don't know why you're honing in on a few things I said and not others.

Because we're still having this discussion: you wouldn't keep trying improving an idea you actually thought was worthless. The mere fact we're having the discussion is evidence you think checked exceptions have some value.