[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)