<story><title>Error Handling Is Hard</title><url>https://www.fpcomplete.com/blog/error-handling-is-hard/</url></story><parent_chain><item><author>adimitrov</author><text>I really, really dislike exceptions.&lt;p&gt;Unchecked exceptions don&amp;#x27;t tell the caller something might go wrong. Fine for Python, where strong guarantees aren&amp;#x27;t a thing anyway, but any statically typed language cannot be content with essentially adding bottom to every single type.&lt;p&gt;Checked exceptions have failed, or at least I haven&amp;#x27;t seen anybody fix their issues. They proliferate spurious exception types in interfaces. They are inflexible, as they usually can&amp;#x27;t be generic. They suck at typing error cases for higher order functions. They&amp;#x27;re big heavy and expensive, so can&amp;#x27;t be used for hot code paths. They&amp;#x27;re &lt;i&gt;exceptions&lt;/i&gt; but more often than not you want to signal expected failure...&lt;p&gt;The list goes on...</text></item><item><author>theamk</author><text>For this case, I actually think Python&amp;#x27;s approach is the best:&lt;p&gt;- Exceptions, so you don&amp;#x27;t need error handling&lt;p&gt;- &lt;i&gt;stack traces&lt;/i&gt; so you know the entire call tree. This is pretty important -- without stack traces, it is very hard to make sense of error messages like &amp;quot;Cannot open file &amp;#x27;none&amp;#x27;&amp;quot; -- the filename is clearly wrong, but where did this come from.&lt;p&gt;- &lt;i&gt;chained exceptions&lt;/i&gt; so you can add context trivially. Doing &amp;quot;try: ... except: raise Exception(&amp;#x27;Cannot load config&amp;#x27;)&amp;quot; will print both error messages and two stack traces, so you know both original error and better description.&lt;p&gt;- &lt;i&gt;verbose by default&lt;/i&gt; so if you don&amp;#x27;t put any effort into error handling, you get lots of details. This is somewhat controversial -- when some people see large stack traces their eyes glaze over and they just stop reading. But as a program&amp;#x27;s author, I love this -- the stack traces are informative enough I can often figure out what&amp;#x27;s wrong immediately.</text></item></parent_chain><comment><author>barrkel</author><text>Spurious exception specifications are the flip side of avoiding not telling the caller something might go wrong. It&amp;#x27;s a fundamental tension and is unavoidable.&lt;p&gt;Failure modes are an abstraction violation; they&amp;#x27;re a function of implementation. That&amp;#x27;s what makes checked exceptions not work, at the end of the day. Information-carrying exceptions reveal implementation details. So a module author must decide between hiding details and wrapping everything up in module-specific exceptions that user code can&amp;#x27;t actually use to make decisions most of the time, or expose implementation details that turn into a versioning problem over time.&lt;p&gt;There&amp;#x27;s roughly two situations for error handling: near the leaf of the call tree, where you have enough context to deal with an error, and need to switch on error type and take compensating action; or near the root of the call tree, in the main loop, where you log errors and terminate requests etc. in a generic way (e.g. 500 response).&lt;p&gt;Exceptions aren&amp;#x27;t ideal for the first situation but are great for the second. Error codes are adequate for the first situation - monadic error types (Result&amp;lt;T&amp;gt;, Either) are a bit better - but suck horribly for the second, because you need to manually unwind, writing boilerplate that should be automatic.&lt;p&gt;And at the limit, error types are isomorphic to checked exceptions, with the same problems, and more - error types introduce an aggregation problem, where multiple errors need to be joined together. You can still get that with exceptions too but it usually requires parallelism.</text></comment>
<story><title>Error Handling Is Hard</title><url>https://www.fpcomplete.com/blog/error-handling-is-hard/</url></story><parent_chain><item><author>adimitrov</author><text>I really, really dislike exceptions.&lt;p&gt;Unchecked exceptions don&amp;#x27;t tell the caller something might go wrong. Fine for Python, where strong guarantees aren&amp;#x27;t a thing anyway, but any statically typed language cannot be content with essentially adding bottom to every single type.&lt;p&gt;Checked exceptions have failed, or at least I haven&amp;#x27;t seen anybody fix their issues. They proliferate spurious exception types in interfaces. They are inflexible, as they usually can&amp;#x27;t be generic. They suck at typing error cases for higher order functions. They&amp;#x27;re big heavy and expensive, so can&amp;#x27;t be used for hot code paths. They&amp;#x27;re &lt;i&gt;exceptions&lt;/i&gt; but more often than not you want to signal expected failure...&lt;p&gt;The list goes on...</text></item><item><author>theamk</author><text>For this case, I actually think Python&amp;#x27;s approach is the best:&lt;p&gt;- Exceptions, so you don&amp;#x27;t need error handling&lt;p&gt;- &lt;i&gt;stack traces&lt;/i&gt; so you know the entire call tree. This is pretty important -- without stack traces, it is very hard to make sense of error messages like &amp;quot;Cannot open file &amp;#x27;none&amp;#x27;&amp;quot; -- the filename is clearly wrong, but where did this come from.&lt;p&gt;- &lt;i&gt;chained exceptions&lt;/i&gt; so you can add context trivially. Doing &amp;quot;try: ... except: raise Exception(&amp;#x27;Cannot load config&amp;#x27;)&amp;quot; will print both error messages and two stack traces, so you know both original error and better description.&lt;p&gt;- &lt;i&gt;verbose by default&lt;/i&gt; so if you don&amp;#x27;t put any effort into error handling, you get lots of details. This is somewhat controversial -- when some people see large stack traces their eyes glaze over and they just stop reading. But as a program&amp;#x27;s author, I love this -- the stack traces are informative enough I can often figure out what&amp;#x27;s wrong immediately.</text></item></parent_chain><comment><author>karatinversion</author><text>My hot take on this is that java checked exceptions are bad because their design predates java generics. Because of the lack of generics, authors of packages such as java.io had to create god-types of exceptions for their general interfaces to throw. A good example is&lt;p&gt;&lt;pre&gt;&lt;code&gt;  public int java.io.Reader.read() throws IOException
&lt;/code&gt;&lt;/pre&gt;
As I see it, the purpose of checked exceptions was to allow declaring expected failure modes in the function signature, so that the programmer (and the compiler!) could check against them - but when my StringReader declares itself capable of throwing an SSLException (subclass of IOException), this benefit is lost. Instead, I must rely on other sources to determine which errors may actually occur, and which I can&amp;#x27;t do anything about - and the latter I must swallow or pollute all of my package&amp;#x27;s function signatures with. If the Reader interface had instead been generic&lt;p&gt;&lt;pre&gt;&lt;code&gt;  java.io.Reader&amp;lt;T extends Throwable&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
read() could be declared as&lt;p&gt;&lt;pre&gt;&lt;code&gt;  public int read() throws T
&lt;/code&gt;&lt;/pre&gt;
This would rescue much, and is something that could be done in modern java; but by the time generics were introduced, all the core packages like java.io were written, and the patterns for how to deal with checked exceptions were set.</text></comment>