Hacker News new | ask | show | jobs
by Mindless2112 1720 days ago
> 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 handle any of these exceptions.

As an argument against checked exceptions, this is nonsense. Hand-waving away making breaking changes to an API because "people don't care" about handling the error conditions. I consider it a sign of the immaturity of the software industry that "proper error handling was too much work, so we didn't" is an acceptable sentiment, let alone an acceptable practice.

4 comments

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 feature, and you just made the programmer write more gobbledy gunk. That doesn't help anybody."

Or as Hejlsberg also says: "You see programmers picking up new APIs that have all these throws clauses, and then you see how convoluted their code gets, and you realize the checked exceptions aren't helping them any."

So, what you maybe need is a different design which the developer-users of the language will actually use in a way that adds value. It's unclear what this different design is, it hasn't been done yet, they say.

Heljsberg again: "Once a better solution is known—and trust me we continue to think about it—we can go back and actually put something in place. I'm a strong believer that if you don't have anything right to say, or anything that moves the art forward, then you'd better just be completely silent and neutral, as opposed to trying to lay out a framework."

The current practice of checked exceptions, as evidenced by what programmers actually do with them, is not helpful. They lay out a case for this. It could be a "sign of immaturity of the software industry" that a helpful design hasn't been found, I dunno, but that doesn't make it any more helpful to do the thing that hasn't been working.

This is a very reasonable argument.

The way to argue against it would be, I guess, to say that they are wrong, many developers DO use checked exceptions in a way that adds value, and provide evidence for this. Or, perhaps, to say that they are right that MOST don't, they may even be right that for MOST actually existing code checked exceptions degrade the quality of code (that is their argument), but that there are a minority of developers who use checked exceptions right (and provide examples of this), and say that justifies putting them in a language. You could argue that, but you'd have to argue it.

> 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<T, E> 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.

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.

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.

Which is the imo correct approach. Instead of unwrapping and rewrapping the exception at the closest level, I want to handle most exceptions in a common place. Eg, in case of a web server that place would give a proper error page to the user whenever an unhandled exception happened in his/her request.

Also, Java’s exceptions are pretty much the exact same sum type as in Rust, just with added syntactic sugar. A method with a throws SomeException signature will have a type of Result<Something> | Error<SomeException>, that gets autounwrapped for you, with the added benefit of giving you a stacktrace by default.

> Java’s exceptions are pretty much the exact same sum type as in Rust, just with added syntactic sugar.

Except Java doesn’t actually return a result object that can be assigned to a variable by default.

And in case of exceptions, why would that be useful?

(For other things, I agree that sum types are cool, and fortunately are supported in Java through sealed classes)

Hejlsberg said it multiple times: Most software developers handle exceptions centrally, e.g. around their event loop.

If an API really throws a new exception which can be handled otherwise than displaying "something went wrong", then I dont think its the task of the programming language. This should be in the release notes.

> 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.

I think exceptions are a not what you should use for regular error conditions that you can handle with the caller. ML descendants are great for that. Sum types with pattern matching to make sure the caller handle the regular error conditions, and exceptions for "catastrophic" things. This with some tooling to show you where exceptions can bubble would be perfet for me.