[HN Gopher] The Trouble with Checked Exceptions (2003)
___________________________________________________________________
The Trouble with Checked Exceptions (2003)
Author : j765
Score : 39 points
Date : 2021-10-10 18:08 UTC (4 hours ago)
(HTM) web link (www.artima.com)
(TXT) w3m dump (www.artima.com)
| karmakaze wrote:
| The Java implementation of checked exceptions suffers from the
| scalability issue as described. As long as each consumed package
| wraps its dependencies checked exceptions into not too many kinds
| this _could_ be workable.
|
| In practice though this isn't how it goes and exceptions in
| signatures grow based on changing versions of dependencies and
| their dependencies so either exceptions signatures change by
| version, or lie.
|
| Two other things that mess all of that up if you manage to get it
| right: (1) RuntimeExceptions which ought to be checked, e.g.
| NumberFormatException and other common (not so exceptional)
| cases, (2) sneaky throws that subvert the unsound type system,
| which can be convenient to work-around the problems above but
| leave you with less confidence overall.
| jez wrote:
| 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 need and desire for checked exceptions fades. I wrote a
| little bit more about how two translate between the two concepts
| and what the benefits of using ad hoc union types are in this
| post in a blog post[2], but my point is that having a proper,
| fully fledged type system feature that composes with all other
| features of the type system is what drives most of the headaches
| away.
|
| [1]: https://james-iry.blogspot.com/2012/02/checked-exceptions-
| mi...
|
| [2]: https://blog.jez.io/union-types-checked-exceptions/
| AzzieElbab wrote:
| It is pretty expensive performance vise
| java-man wrote:
| 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.
| jez wrote:
| 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.
| java-man wrote:
| 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.
| carlmr wrote:
| 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.
| Mindless2112 wrote:
| > _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.
| jrochkind1 wrote:
| 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.
| Mindless2112 wrote:
| > _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.
| TOGoS wrote:
| > 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.
| skeeks wrote:
| 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.
| fennecfoxen wrote:
| I feel a lot of the problem here is that someone make the
| FooLibrary that does some file system call and sometimes throws
| some IOError. Later on a new backend goes over the network and it
| throws a NetworkError now too.
|
| This is a leaked abstraction. These are both a kind of FooError.
| If you're using a strong enough type system that cares about
| these things, you should be using it to invest in that sort of
| strong encapsulation, too. Each API layer should be a translation
| layer.
|
| Needless to say, this is a fair bit of work, and takes a fair
| amount of rigor, so it usually won't happen.
| im3w1l wrote:
| I 95% agree with you. But I think it's just slightly more
| nuanced. If you tell FooLibrary to open a FooFile, then
| throwing FileNotFoundException is acceptable to signal that
| that file is not found. In a sense it's just passing along an
| exception that was meant for you.
|
| On the other hand, if FooLibrary tries to read some config file
| or fetch metadata over the internet, then that's a sort of
| detail that it shouldn't bother the caller with. It should
| either handle the exception or translate it to a FooException.
| onimishra wrote:
| An old but goodie. While Hejlsberg touches on a fair amount of
| good points in this discussion, I've never agreed with the end
| result.
|
| He went on to make Typescript - making sure that JS has types, so
| when making method calls you could have the compiler tell you
| when you did something wrong. Again, errors/exceptions did not
| get a throw clause, making it impossible to model the error state
| that the language provides. You can describe, in detail, the data
| for successful run, but are unable to describe the data for any
| error state. If the goal was to make the system more sound, I
| have a hard time seeing why the error state is not taken into
| account.
|
| A lot of the described (and for myself experienced) cases against
| checked exceptions comes from external libraries or the language
| itself. IOException has a special place in hell, but for my own
| business logic (or inherited legacy code) in an application that
| spans thousands of files and classes, I would very much like to
| describe and be made aware of the error state throughout my
| application.
|
| In Java, if I introduce a new business logic error state, all the
| places in my http (or cli or whatever) layer that uses that
| business logic will get highlighted for me, and I can then map it
| accordingly. In C#, that is not the case. If I don't want checked
| exceptions, I can always catch it and throw a runtime exception -
| but I have the option. As a developer who likes to think I know
| what I'm doing, I would at least like the option. In C#, that
| decision was never mine.
|
| With TS, we have a system that lives around being configurable.
| One day, I would really like to see this being up to the
| developer and a parameter in the tsconfig file, maybe with a
| configurable list of error types to be considered
| RuntimeExceptions. That way, if I don't agree with a library's
| use of the feature, I can tell TS to not report them by
| considering them Runtime.
|
| Might just be because I use an architecture that actually favors
| CheckedExceptions, but not being able to describe the error
| states of my business logic really grinds my gears ;)
___________________________________________________________________
(page generated 2021-10-10 23:00 UTC)