Live data from Hacker News

The Trouble with Checked Exceptions (2003)

artima.com

11–20 of 35 posts

Re: The Trouble with Checked Exceptions (2003)

#11
post #6

I like James Iry’s take on checked exceptions here[1] which basically boils down to this: > The throws clause is the only point in the entire Java language that allows union types. You can tack “throws A,B,C” onto a method signature meaning it might throw A or B or C, but outside of the throws clause you cannot say “type A or B or C” in Java. In languages with better support for ad hoc union types, I think both the n…

class A extends UnionBase;

class B extends UnionBase;

public UnionBase someMethod();

furthermore, UnionBase might have isA() and isB() if need be.

So, strictly speaking, your statement is incorrect.

Re: The Trouble with Checked Exceptions (2003)

#12
post #6

I like James Iry’s take on checked exceptions here[1] which basically boils down to this: > The throws clause is the only point in the entire Java language that allows union types. You can tack “throws A,B,C” onto a method signature meaning it might throw A or B or C, but outside of the throws clause you cannot say “type A or B or C” in Java. In languages with better support for ad hoc union types, I think both the n…

class A extends UnionBase; class B extends UnionBase; public UnionBase someMethod(); furthermore, UnionBase might have isA() and isB() if need be. So, strictly speaking, your statement is incorrect.

In this case UnionBase is not ad hoc: you had to declare a name for it up front. Ad hoc means you can write the union type wherever types can be written. For example, it’s not possible to write this:

    public (A | B) someMethod();
in Java.

Re: The Trouble with Checked Exceptions (2003)

#13

> Bill Venners: But aren't you breaking their code in that case anyway, even in a language without checked exceptions? If the new version of foo is going to throw a new exception that clients should think about handling, isn't their code broken just by the fact that they didn't expect that exception when they wrote the code? > Anders Hejlsberg: No, because in a lot of cases, people don't care. They're not going to ha…

> Hand-waving away making breaking changes to an API because "people don't care" about handling the error conditions

Generally, adding more specific exception types, so long as they are subclasses of exception types already handled, would not be a breaking API change. Your general exception handler would still run, and you could choose to do something special with the new exceptions if that helps your calling program be better.

Changing how a certain error case is represented such that a previously triggered handler is no longer triggered might be considered breaking, though.

Re: The Trouble with Checked Exceptions (2003)

#14
post #12

Earlier quoted context omitted.

class A extends UnionBase; class B extends UnionBase; public UnionBase someMethod(); furthermore, UnionBase might have isA() and isB() if need be. So, strictly speaking, your statement is incorrect.

In this case UnionBase is not ad hoc: you had to declare a name for it up front. Ad hoc means you can write the union type wherever types can be written. For example, it’s not possible to write this: public (A | B) someMethod(); in Java.

Yes, this is the basic benefit of typed languages. I would not want to refactor a 20 year old code base without type safety - I do want to know what's being returned.

I also want my tools to know what's being returned, as well as my compiler.

Re: The Trouble with Checked Exceptions (2003)

#15
post #12

Earlier quoted context omitted.

In this case UnionBase is not ad hoc: you had to declare a name for it up front. Ad hoc means you can write the union type wherever types can be written. For example, it’s not possible to write this: public (A | B) someMethod(); in Java.

Yes, this is the basic benefit of typed languages. I would not want to refactor a 20 year old code base without type safety - I do want to know what's being returned. I also want my tools to know what's being returned, as well as my compiler.

But in languages supporting this you do know that it's either A or B and you can use match expressions to deal with both cases.

Usually these are the languages with more focus on type safety, like OCaml, Haskell and Rust.

Re: The Trouble with Checked Exceptions (2003)

#16

> Bill Venners: But aren't you breaking their code in that case anyway, even in a language without checked exceptions? If the new version of foo is going to throw a new exception that clients should think about handling, isn't their code broken just by the fact that they didn't expect that exception when they wrote the code? > Anders Hejlsberg: No, because in a lot of cases, people don't care. They're not going to ha…

When writing a programming langauge, your users are programmers. You can wish they had different behavior than they have, but wishing wont' make them do it. At the present point in history, the interviewees say, there is lots of evidence of what programmers actually do with checked exceptions, and that's what they are speaking to, very explicitly. What they actually do are things "That just completely defeats the fea…

> what programmers actually* do with checked exceptions*

If the only trade-off considered is 'writing "gobbledy gunk" to handle exceptions poorly' vs 'not handling them at all' then, of course, checked exceptions will look bad.

If the trade-off is whether the compiler will be able to tell me that I'm not handling an exception, well, I want the compiler to help me out. People writing low-consequence code can sprinkle "throws Exception" everywhere.

Without checked exceptions, it becomes my job to ensure that exceptions are handled, and I am nowhere near as thorough as the compiler.

> what you maybe need is a different design*

Could be. Perhaps exceptions on the whole are not a good error mechanism because of the way programmers think about them.

Picking two HN favorites, Rust has Result and Zig has error sets, both of which effectively work a lot like checked exceptions but with better syntax (and without the bad rap). try/catch is clunky by comparison.

Re: The Trouble with Checked Exceptions (2003)

#17
post #6

I like James Iry’s take on checked exceptions here[1] which basically boils down to this: > The throws clause is the only point in the entire Java language that allows union types. You can tack “throws A,B,C” onto a method signature meaning it might throw A or B or C, but outside of the throws clause you cannot say “type A or B or C” in Java. In languages with better support for ad hoc union types, I think both the n…

It is pretty expensive performance vise

Is it? The VM is already already storing the tags on objects to be able to down cast. For example, in Java, the JVM is already storing the bits to remember that your `x` is a `Child` to safely raise an exception for

    Child castToChild(Object x) {
        return (Child)x;
    }
So at least it's not expensive from the standpoint of "uses more memory."

Maybe you're saying that it's more expensive because dynamic dispatch on a type like (A | B) will be slower than static dispatch on a type like A, but most languages lacking ad hoc union types will already have other ways to do dynamic dispatch (parent classes, interfaces, etc.) so it's not like adding ad hoc union types solely incentivizes people to write slower, dynamically dispatched code.

Maybe when you say "performance" you mean that the performance of the type checker is slower? That's definitely true—as ad hoc union types get larger (dozens, hundreds, heaven forbid thousands of variants) the type checker will definitely struggle.

That being said, there have been some impressive optimizations in practice to speed these up (I've spoken with members of the TypeScript team touting some really cool improvements to their union types, and I've seen members of my team submit similar but not quite as good improvements to the union types in Sorbet for Ruby). So I definitely agree that a priori, they're going to be slower to type check, but I think that they can be made fast in common cases, and their benefit in terms of power added to the type system is just a really, really good tradeoff.

So I'm not sure I agree on face value that adding ad hoc union types to a language necessarily come with a performance expense.

Re: The Trouble with Checked Exceptions (2003)

#18

Earlier quoted context omitted.

When writing a programming langauge, your users are programmers. You can wish they had different behavior than they have, but wishing wont' make them do it. At the present point in history, the interviewees say, there is lots of evidence of what programmers actually do with checked exceptions, and that's what they are speaking to, very explicitly. What they actually do are things "That just completely defeats the fea…

> what programmers actually* do with checked exceptions* If the only trade-off considered is 'writing "gobbledy gunk" to handle exceptions poorly' vs 'not handling them at all' then, of course, checked exceptions will look bad. If the trade-off is whether the compiler will be able to tell me that I'm not handling an exception, well, I want the compiler to help me out. People writing low-consequence code can sprinkle…

The crucial difference with Rust's Result (I don't know Zig well enough) is that Result isn't about control flow.

Exceptions unavoidably and deliberately change control flow.

Suppose you're in a loop twiddling zarks. In Rust, twiddling a zark gives you a Result and if the Result isn't Ok then that's an error. But Rust doesn't care what - if anything - you do with the error, it just won't allow you to pretend the error was Ok (because it isn't). You can count up all your Results and consider what fraction were Ok. You can filter out any that weren't Ok. You can ignore the Result altogether. Or, if you find one that isn't Ok you could give up twiddling zarks immediately. Rust doesn't mind, Results are just data, do whatever you want with it.

But in a language with exceptions, checked or not, each time there's a problem twiddling a zark the exception jumps the program to somewhere else to "handle" the exception - and it's on you, the programmer, to manage that, by e.g. wrapping the zark twiddling in a try-catch block.

Re: The Trouble with Checked Exceptions (2003)

#19
post #17

Earlier quoted context omitted.

It is pretty expensive performance vise

Is it? The VM is already already storing the tags on objects to be able to down cast. For example, in Java, the JVM is already storing the bits to remember that your `x` is a `Child` to safely raise an exception for Child castToChild(Object x) { return (Child)x; } So at least it's not expensive from the standpoint of "uses more memory." Maybe you're saying that it's more expensive because dynamic dispatch on a type l…

My understanding is that it is not the exceptions themselves, it is filling up stack traces which is considered performance taxing thing to do in jvm

Re: The Trouble with Checked Exceptions (2003)

#20

Earlier quoted context omitted.

> what programmers actually* do with checked exceptions* If the only trade-off considered is 'writing "gobbledy gunk" to handle exceptions poorly' vs 'not handling them at all' then, of course, checked exceptions will look bad. If the trade-off is whether the compiler will be able to tell me that I'm not handling an exception, well, I want the compiler to help me out. People writing low-consequence code can sprinkle…

The crucial difference with Rust's Result (I don't know Zig well enough) is that Result isn't about control flow. Exceptions unavoidably and deliberately change control flow. Suppose you're in a loop twiddling zarks. In Rust, twiddling a zark gives you a Result and if the Result isn't Ok then that's an error. But Rust doesn't care what - if anything - you do with the error, it just won't allow you to pretend the erro…

Error returns and checked exceptions are isomorphic. There's nothing you can do with one that you can't do with the other.

But I agree with the underlying point you're making. The error mechanism that a language provides determines how a programmer will think about handling errors. Exceptions make you think about error handling as control flow. Error returns make you think about error handling as unwrapping data.

Post reply on HN