Exception handling (programming): Difference between revisions

Content deleted Content added
References: Resolving Category:Harv and Sfn no-target errors. When copying short form refs between articles, remember to copy the required cites
m Fix a syntax error
 
(59 intermediate revisions by 24 users not shown)
Line 1:
{{Short description|Computer programming concept}}
{{broader|Exception handling}}
 
In [[computer programming]], several [[programming language|language]] mechanisms exist for '''exception handling'''. The term ''exception'' is typically used to denote a data structure storing information about an exceptional condition. One mechanism to transfer control, or ''raise'' an exception, is known as a ''throw''; the exception is said to be ''thrown''. Execution is transferred to a ''catch''.
 
== Usage ==
Programming languages differ substantially in their notion of what an exception is. Contemporary languages can roughly be divided into two groups:<ref name="Kiniry">{{Cite book | doi = 10.1007/11818502_16| chapter = Exceptions in Java and Eiffel: Two Extremes in Exception Design and Application| title = Advanced Topics in Exception Handling Techniques| volume = 4119| pages = 288–300| series = Lecture Notes in Computer Science| year = 2006| last1 = Kiniry | first1 = J. R. | isbn = 978-3-540-37443-5|url=http://staffwww.dcs.shef.ac.uk/people/A.Simons/remodel/papers/ExceptionsInEiffelAndJava.pdf}}</ref><ref group=note>PL/I used dynamically scoped exceptions. PL/I exception handling included events that are not errors, e.g., attention, end-of-file, modification of listed variables.{{Citation needed|date=June 2020}}</ref>
 
* Languages where exceptions are designed to be used as flow control structures: Ada, Modula-3, ML, OCaml, PL/I, Python, and Ruby fall in this category. For example, [[Iterator#Python|Python's iterators]] throw StopIteration exceptions to signal that there are no further items produced by the iterator.<ref>{{cite web |title=Built-in Exceptions — Python 3.10.4 documentation |url=https://docs.python.org/3/library/exceptions.html#StopIteration |website=docs.python.org |access-date=17 May 2022}}</ref>
Programming languages differ substantially in their notion of what an exception is. Exceptions can be used to represent and handle abnormal, unpredictable, erroneous situations, but also as flow control structures to handle normal situations. For example, [[Iterator#Python|Python's iterators]] throw StopIteration exceptions to signal that there are no further items produced by the iterator.<ref>{{cite web |title=Built-in Exceptions — Python 3.10.4 documentation |url=https://docs.python.org/3/library/exceptions.html#StopIteration |website=docs.python.org |access-date=17 May 2022}}</ref> There is disagreement within many languages as to what constitutes idiomatic usage of exceptions. For example, Joshua Bloch states that Java's exceptions should only be used for exceptional situations,<ref name="EffectiveJava">
* Languages where exceptions are only used to handle abnormal, unpredictable, erroneous situations: C++,<ref>{{cite web|url=http://www.stroustrup.com/bs_faq2.html#exceptions-what-not|title=Stroustrup: C++ Style and Technique FAQ|website=www.stroustrup.com|access-date=5 May 2018|url-status=live|archive-url=https://web.archive.org/web/20180202012417/http://www.stroustrup.com/bs_faq2.html#exceptions-what-not|archive-date=2 February 2018}}</ref> Java,<ref name="EffectiveJava">
{{cite book
| last = Bloch
Line 18 ⟶ 19:
| chapter-url = https://archive.org/details/effectivejava00bloc_0/page/241
| edition = Second
}}</ref> but Kiniry observes that Java's built-in {{java|FileNotFoundException}} is not at all an exceptional event.<ref name="Kiniry">{{Cite book | doi = 10.1007/11818502_16| chapter = Exceptions in Java and Eiffel: Two Extremes in Exception Design and Application| title = Advanced Topics in Exception Handling Techniques| volume = 4119| pages = 288–300| series = Lecture Notes in Computer Science| year = 2006| last1 = Kiniry | first1 = J. R. | isbn = 978-3-540-37443-5| s2cid = 33283674|url=http://staffwww.dcs.shef.ac.uk/people/A.Simons/remodel/papers/ExceptionsInEiffelAndJava.pdf}}</ref> Similarly, Bjarne Stroustrup, author of C++, states that C++ exceptions should only be used for error handling, as this is what they were designed for,<ref>{{cite web|url=http://www.stroustrup.com/bs_faq2.html#exceptions-what-not|title=Stroustrup: C++ Style and Technique FAQ|website=www.stroustrup.com|access-date=5 May 2018|url-status=live|archive-url=https://web.archive.org/web/20180202012417/http://www.stroustrup.com/bs_faq2.html#exceptions-what-not|archive-date=2 February 2018}}</ref> but Kiniry observes that many modern languages such as Ada, C++,
}}</ref> C#, Common Lisp, Eiffel, and Modula-2.
Modula-3, ML and OCaml, Python, and Ruby use exceptions for flow control. Some languages such as Eiffel, C#, Common Lisp, and Modula-2 have made a concerted effort to restrict their usage of exceptions, although this is done on a social rather than technical level.<ref name="Kiniry">{{Cite book | doi = 10.1007/11818502_16| chapter = Exceptions in Java and Eiffel: Two Extremes in Exception Design and Application| title = Advanced Topics in Exception Handling Techniques| volume = 4119| pages = 288–300| series = Lecture Notes in Computer Science| year = 2006| last1 = Kiniry | first1 = J. R. | isbn = 978-3-540-37443-5| s2cid = 33283674|url=http://staffwww.dcs.shef.ac.uk/people/A.Simons/remodel/papers/ExceptionsInEiffelAndJava.pdf}}</ref>
 
== History ==
The earliest [[IBM]] [[Fortran]] compilers had statements for testing exceptional conditions. These included the <code>IF ACCUMULATOR OVERFLOW</code>, <code>IF QUOTIENT OVERFLOW</code>, and <code>IF DIVIDE CHECK</code> statements. In the interest of machine independence, they were not included in FORTRAN IV nor the Fortran 66 Standard. However since Fortran 2003 it is possible to test for numerical issues via calls to functions in the <code>IEEE_EXCEPTIONS</code> module.
Software exception handling developed in the 1960s and 1970s. [[LISP 1.5]] (1958-1961)<ref>{{cite web |last1=McCarthy |first1=John |title=History of Lisp |url=http://www-formal.stanford.edu/jmc/history/lisp/node1.html |website=www-formal.stanford.edu |access-date=13 January 2022 |date=12 February 1979}}</ref> allowed exceptions to be raised by the <code>ERROR</code> pseudo-function, similarly to errors raised by the interpreter or compiler. Exceptions were caught by the <code>ERRORSET</code> keyword, which returned <code>NIL</code> in case of an error, instead of terminating the program or entering the debugger.<ref>{{cite book|
 
Software exception handling continued to be developed in the 1960s and 1970s. [[LISP 1.5]] (1958-1961)<ref>{{cite web |last1=McCarthy |first1=John |title=History of Lisp |url=http://www-formal.stanford.edu/jmc/history/lisp/node1.html |website=www-formal.stanford.edu |access-date=13 January 2022 |date=12 February 1979}}</ref> allowed exceptions to be raised by the <code>ERROR</code> pseudo-function, similarly to errors raised by the interpreter or compiler. Exceptions were caught by the <code>ERRORSET</code> keyword, which returned <code>NIL</code> in case of an error, instead of terminating the program or entering the debugger.<ref>{{cite book|
first1=John|last1=McCarthy|first2=Michael I.|last2=Levin|first3=Paul W.|last3=Abrahams|first4=Daniel J.|last4=Edwards|first5=Timothy P.|last5=Hart
|title=LISP 1.5 programmer's manual |date=14 July 1961 |url=http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual-1961.07.14.pdf#page=58 |access-date=13 January 2022}}</ref>
Line 40 ⟶ 44:
{{Further|Exception handling syntax}}
 
Many computer languages have built-in syntactic support for exceptions and exception handling. This includes [[ActionScript]], [[Ada programming language|Ada]], [[BlitzMax]], [[C++]], [[C Sharp (programming language)|C#]], [[Clojure]], [[COBOL]], [[D programming language|D]], [[ECMAScript]], [[Eiffel (programming language)|Eiffel]], [[Java (programming language)|Java]], [[ML programming language|ML]], [[Object Pascal]] (e.g. [[Delphi (programming language)|Delphi]], [[Free Pascal]], and the like), [[PowerBuilder]], [[Objective-C]], [[OCaml]], Perl,<ref>{{Cite web |title=Exceptions - Documentation for exception handling in Perl |url=https://metacpan.org/pod/Exceptions}}</ref> [[PHP]] (as of version 5), [[PL/I]], [[PL/SQL]], [[Prolog]], [[Python (programming language)|Python]], [[REALbasic]], [[Ruby (programming language)|Ruby]], [[Scala (programming language)|Scala]], [[Seed7]], [[Smalltalk]], [[Tcl]], [[Visual Prolog]] and most [[.NET Framework|.NET]] languages.
 
Excluding minor syntactic differences, there are only a couple of exception handling styles in use. In the most popular style, an exception is initiated by a special statement (<code>throw</code> or <code>raise</code>) with an exception object (e.g. with Java or Object Pascal) or a value of a special extendable enumerated type (e.g. with Ada or SML). The scope for exception handlers starts with a marker clause (<code>try</code> or the language's block starter such as <code>begin</code>) and ends in the start of the first handler clause (<code>catch</code>, <code>except</code>, <code>rescue</code>). Several handler clauses can follow, and each can specify which exception types it handles and what name it uses for the exception object. As a minor variation, some languages use a single handler clause, which deals with the class of the exception internally.
Line 50 ⟶ 54:
In its whole, exception handling code might look like this (in [[Java (programming language)|Java]]-like [[pseudocode]]):
 
<syntaxhighlight lang="CSharpJava">
try {
lineScanner stdin = console.readLinenew Scanner(System.in);
String line = stdin.nextLine();
 
if (line.length() == 0) {
throw new EmptyLineExceptionIOException("The line read from console was empty!");
}
 
consoleSystem.printLineout.printf("Hello %s!\n" %, line);
System.out.println("The task executed successfully.");
}
} catch (EmptyLineExceptionIOException e) {
consoleSystem.printLineout.println("Hello!");
} catch (Exception e) {
}
System.out.printf("Error: %s\n", e.getMessage());
catch (Exception e) {
} finally {
console.printLine("Error: " + e.message());
System.out.println("The program is now terminating.");
}
else {
console.printLine("The program ran successfully.");
}
finally {
console.printLine("The program is now terminating.");
}
</syntaxhighlight>
 
C does not have try-catch exception handling, but uses [[return code]]s for error checking. The [[Setjmp.h|<code>setjmp</code> and <code>longjmp</code>]] standard library functions can be used to implement try-catch handling via macros.<ref>{{citeCite journaltech |last1=Roberts |first1=Eric S. |title=Implementing Exceptions in C |date=21 March 1989report |url=http://bitsavers.informatik.uni-stuttgart.de/pdf/dec/tech_reports/SRC-RR-40.pdf |access-title=Implementing Exceptions in C |last=Roberts |first=Eric S. |date=421 JanuaryMarch 20221989 |publisher=[[DEC Systems Research Center]] |id=SRC-RR-40 |access-date=4 January 2022}}</ref>
 
[[Perl]] 5 uses <code>die</code> for <code>throw</code> and {{code|eval {} if ($@) {}|perl}} for try-catch. It has CPAN modules that offer try-catch semantics.<ref>{{cite book |last1=Christiansen |first1=Tom |last2=Torkington |first2=Nathan |title=Perl cookbook |date=2003 |publisher=O'Reilly |___location=Beijing |isbn=0-596-00313-7 |edition=2nd |url=https://docstore.mik.ua/orelly/perl4/cook/ch10_13.htm |chapter=10.12. Handling Exceptions}}</ref>
Line 93:
The implementation of exception handling in programming languages typically involves a fair amount of support from both a code generator and the [[runtime system]] accompanying a compiler. (It was the addition of exception handling to C++ that ended the useful lifetime of the original C++ compiler, [[Cfront]].<ref>[[Scott Meyers]], [http://www.artima.com/cppsource/top_cpp_software.html The Most Important C++ Software...Ever] {{webarchive|url=https://web.archive.org/web/20110428221802/http://www.artima.com/cppsource/top_cpp_software.html |date=2011-04-28 }}, 2006</ref>) Two schemes are most common. The first, ''{{visible anchor|dynamic registration}}'', generates code that continually updates structures about the program state in terms of exception handling.<ref>D. Cameron, P. Faust, D. Lenkov, M. Mehta, "A portable implementation of C++ exception handling", ''Proceedings of the C++ Conference'' (August 1992) [[USENIX]].</ref> Typically, this adds a new element to the [[Call stack|stack frame layout]] that knows what handlers are available for the function or method associated with that frame; if an exception is thrown, a pointer in the layout directs the runtime to the appropriate handler code. This approach is compact in terms of space, but adds execution overhead on frame entry and exit. It was commonly used in many Ada implementations, for example, where complex generation and runtime support was already needed for many other language features. Microsoft's 32-bit [[Structured Exception Handling]] (SEH) uses this approach with a separate exception stack.<ref>{{cite web|url=http://stoned-vienna.com/html/index.php?page=windows-exception-handling|author=Peter Kleissner|title=Windows Exception Handling - Peter Kleissner|date=February 14, 2009|access-date=2009-11-21 |archive-url=https://web.archive.org/web/20131014204335/http://stoned-vienna.com/html/index.php?page=windows-exception-handling |archive-date=October 14, 2013 |url-status=dead}}, ''Compiler based Structured Exception Handling'' section</ref> Dynamic registration, being fairly straightforward to define, is amenable to [[proof of correctness]].<ref>Graham Hutton, Joel Wright, "[http://www.cs.nott.ac.uk/~gmh/exceptions.pdf Compiling Exceptions Correctly] {{webarchive|url=https://web.archive.org/web/20140911173720/http://www.cs.nott.ac.uk/~gmh/exceptions.pdf |date=2014-09-11 }}". ''Proceedings of the 7th International Conference on Mathematics of Program Construction'', 2004.</ref>
 
The second scheme, and the one implemented in many production-quality C++ compilers and 64-bit Microsoft [[Structured Exception Handling|SEH]], is a {{visible anchor|table-driven approach|text=''table-driven'' approach}}. This creates static tables at [[compile time]] and [[link time]] that relate ranges of the [[program counter]] to the program state with respect to exception handling.<ref>{{cite journal | title=Exception handling – Supporting the runtime mechanism | last=Lajoie | first= Josée | journal=C++ Report | volume=6 | issue=3 | date=March–April 1994}}</ref> Then, if an exception is thrown, the runtime system looks up the current instruction ___location in the tables and determines what handlers are in play and what needs to be done. This approach minimizes executive overhead for the case where an exception is not thrown. This happens at the cost of some space, but this space can be allocated into read-only, special-purpose data sections that are not loaded or relocated until an exception is actually thrown.<ref name=cppeh>{{cite journal | title=Optimizing away C++ exception handling | last=Schilling | first=Jonathan L. | journal=[[SIGPLAN Notices]] | volume=33 | issue=8 | date=August 1998 | pages=40–47 | doi=10.1145/286385.286390| s2cid=1522664 | doi-access=free }}</ref> The ___location (in memory) of the code for handling an exception need not be located within (or even near) the region of memory where the rest of the function's code is stored. So if an exception is thrown then a performance hit – roughly comparable to a function call<ref name=MiscrosoftDocsExceptions>{{cite web|title=Modern C++ best practices for exceptions and error handling|work=Microsoft|date=8 March 2021|access-date=21 March 2022|url=https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp}}</ref> – may occur if the necessary exception handling code needs to be loaded/cached. However, this scheme has minimal performance cost if no exception is thrown. Since exceptions in C++ are supposed to be ''exceptional'' (i.e. uncommon/rare) events, the phrase "zero-cost exceptions"<ref group=note>There is "zero [processing] cost" only if no exception is throw (although there will be a memory cost since memory is needed for the lookup table). There is a (potentially significant) cost if an exception is thrown (that is, if <code>throw</code> is executed). Implementing exception handling may also limit the possible [[Optimizing compiler|compiler optimizations]] that may be performed.</ref> is sometimes used to describe exception handling in C++. Like [[runtime type identification]] (RTTI), exceptions might not adhere to C++'s [https://en.cppreference.com/w/cpp/language/Zero-overhead_principle zero-overhead principle] as implementing exception handling at run-time requires a non-zero amount of memory for the lookup table.<ref name=StroustrupExceptions2019>{{cite web|last=Stroustrup|first=Bjarne|author-link=Bjarne Stroustrup|title=C++ exceptions and alternatives|date=18 November 2019|access-date=23 March 2022|url=http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1947r0.pdf}}</ref> For this reason, exception handling (and RTTI) can be disabled in many C++ compilers, which may be useful for systems with very limited memory<ref name=StroustrupExceptions2019 /> (such as [[embedded system]]s). This second approach is also superior in terms of achieving [[thread safety]]{{Citation needed|date=September 2012}}.
 
In comparison to C++ where any type may be thrown and caught, in Java only types extending <code>Throwable</code> can be thrown and caught, and <code>Throwable</code> has two direct descendants: <code>Error</code> (indicating a serious problem a reasonable program need not catch), and <code>Exception</code> (any other condition that a reasonable program may want to catch and handle). <code>Error</code> is typically reserved for extremely serious problems beyond the scope of the program, such as <code>OutOfMemoryError</code>, <code>ThreadDeath</code>, or <code>VirtualMachineError</code>.
 
Other definitional and implementation schemes have been proposed as well. For languages that support [[metaprogramming]], approaches that involve no overhead at all (beyond the already present support for [[reflection (computer science)|reflection]]) have been advanced.<ref>M. Hof, H. Mössenböck, P. Pirkelbauer, "[http://www.ssw.uni-linz.ac.at/Research/Papers/Hof97b.html Zero-Overhead Exception Handling Using Metaprogramming] {{webarchive|url=https://web.archive.org/web/20160303180327/http://www.ssw.uni-linz.ac.at/Research/Papers/Hof97b.html |date=2016-03-03 }}", ''Proceedings SOFSEM'97'', November 1997, ''Lecture Notes in Computer Science 1338'', pp. 423-431.</ref>
Line 139 ⟶ 141:
Although exceptions in Eiffel have a fairly clear philosophy, Kiniry (2006) criticizes their implementation because "Exceptions that are part of the language definition are represented by INTEGER values, developer-defined exceptions by STRING values. [...] Additionally, because they are basic values and not objects, they have no inherent semantics beyond that which is expressed in a helper routine which necessarily cannot be foolproof because of the representation overloading in effect (e.g., one cannot
differentiate two integers of the same value)."<ref name="Kiniry"/>
 
[[C++26]] adds support for contracts, which are used as follows.<ref>{{cite web|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2900r14.pdf|title=Contracts for C++|date=13 February 2025}}</ref>
<syntaxhighlight lang="cpp">
int f(const int x)
pre(x != 1) // a precondition assertion
post(r : r == x && r != 2) // a postcondition assertion; r names the result object of f
{
contract_assert(x != 3); // an assertion statement
return x;
}
Each contract
</syntaxhighlight>
 
== Uncaught exceptions ==
Contemporary applications face many design challenges when considering exception handling strategies. Particularly in modern enterprise level applications, exceptions must often cross process boundaries and machine boundaries. Part of designing a solid exception handling strategy is recognizing when a process has failed to the point where it cannot be economically handled by the software portion of the process.<ref>All Exceptions Are Handled, Jim Wilcox, {{cite web |url=https://www.granitestateusersgroups.net/2008/02/21/all-exceptions-are-handled/ |title=All Exceptions Are Handled |date=22 February 2008 }}</ref>
 
If an exception is thrown and not caught (operationally, an exception is thrown when there is no applicable handler specified), the uncaught exception is handled by the runtime; the routine that does this is called the '''{{visible anchor|uncaught exception handler}}'''.<ref name="cocoa">''Mac Developer Library'', "[https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Exceptions/Concepts/UncaughtExceptions.html Uncaught Exceptions] {{webarchive|url=https://web.archive.org/web/20160304111516/https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Exceptions/Concepts/UncaughtExceptions.html |date=2016-03-04 }}"</ref><ref>''MSDN'', [https://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception(v=vs.110).aspx AppDomain.UnhandledException Event] {{webarchive|url=https://web.archive.org/web/20160304131615/https://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception(v=vs.110).aspx |date=2016-03-04 }}</ref> The most common default behavior is to terminate the program and print an error message to the console, usually including debug information such as a string representation of the exception and the [[stack trace]].<ref name="cocoa"/><ref>''The Python Tutorial'', "[https://docs.python.org/2/tutorial/errors.html 8. Errors and Exceptions] {{webarchive|url=https://web.archive.org/web/20150901043830/https://docs.python.org/2/tutorial/errors.html |date=2015-09-01 }}"</ref><ref>{{cite web|url=http://www.javapractices.com/topic/TopicAction.do?Id=229|title=Java Practices -> Provide an uncaught exception handler|website=www.javapractices.com|access-date=5 May 2018|url-status=live|archive-url=https://web.archive.org/web/20160909002524/http://www.javapractices.com/topic/TopicAction.do?Id=229|archive-date=9 September 2016}}</ref> This is often avoided by having a top-level (application-level) handler (for example in an [[event loop]]) that catches exceptions before they reach the runtime.<ref name="cocoa"/><ref name="pmotw">PyMOTW (Python Module Of The Week), "[https://pymotw.com/2/sys/exceptions.html Exception Handling] {{webarchive|url=https://web.archive.org/web/20150915032624/https://pymotw.com/2/sys/exceptions.html |date=2015-09-15 }}"</ref>
Line 152 ⟶ 166:
 
== Checked exceptions ==
[[Java (programming language)|Java]] introduced the notion of checked exceptions,<ref>{{cite web |url=http://answers.google.com/answers/threadview?id=26101 |title=Google Answers: The origin of checked exceptions |access-date=2011-12-15 |url-status=live |archive-url=http://archive.wikiwix.com/cache/20110806090553/http://answers.google.com/answers/threadview?id=26101 |archive-date=2011-08-06 }}</ref><ref>Java Language Specification, chapter 11.2. http://java.sun.com/docs/books/jls/third_edition/html/exceptions.html#11.2 {{webarchive|url=https://web.archive.org/web/20061208042454/http://java.sun.com/docs/books/jls/third_edition/html/exceptions.html |date=2006-12-08 }}</ref> which are special classes of exceptions. In Java, a checked exception specifically is any <code>Exception</code> that does not extend <code>RuntimeException</code>. The checked exceptions that a method may raise must be part of the method's [[Type signature|signature]]. For instance, if a method might throw an {{Java|IOException}}, it must declare this fact explicitly in its method signature. Failure to do so raises a compile-time error. AccordingThis towould Hanspeterbe Mössenböck,declared checkedlike exceptions are less convenient but more robust.<ref>{{cite webso:
 
<syntaxhighlight lang="Java">
public void operateOnFile(File f) throws IOException {
// ...
}
</syntaxhighlight>
 
According to Hanspeter Mössenböck, checked exceptions are less convenient but more robust.<ref>{{cite web
|access-date = 2011-08-05
|date = 2002-03-25
Line 173 ⟶ 195:
* Scalability: In a hierarchical design, each systems may have several subsystems. Each subsystem may throw several exceptions. Each parent system must deal with the exceptions of all subsystems below it, resulting in an exponential number of exceptions to be dealt with. Checked exceptions require all of these exceptions to be dealt with explicitly.
 
To work around these, Hejlsberg says programmers resort to circumventing the feature by using a {{C++|throws Exception}} declaration. Another circumvention is to use a {{C++|<syntaxhighlight lang="java" inline>try { ... } catch (Exception e) {<nowiki> ... } </nowikisyntaxhighlight> (or even a <syntaxhighlight lang="java" inline>try { ... } catch (Throwable t) { ... } </syntaxhighlight>) handler.<ref name=Trouble/> This is referred to as catch-all exception handling or '''Pokémon exception handling''' after [[Pokémon|the show]]'s catchphrase "[[Pokémon Theme|Gotta Catch ‘Em'Em All!]]".<ref>{{cite book |last1=Juneau |first1=Josh |title=Java 9 Recipes: A Problem-Solution Approach |date=31 May 2017 |publisher=Apress |isbn=978-1-4842-1976-8 |page=226 |url=https://books.google.com/books?id=TSYmDwAAQBAJ&pg=PA226 |language=en}}</ref> The Java Tutorials discourage catch-all exception handling as it may catch exceptions "for which the handler was not intended".<ref>{{cite web |url=http://download.oracle.com/javase/tutorial/essential/exceptions/advantages.html |title=Advantages of Exceptions (The Java™ Tutorials : Essential Classes : Exceptions) |publisher=Download.oracle.com |access-date=2011-12-15 |url-status=live |archive-url=https://web.archive.org/web/20111026121217/http://download.oracle.com/javase/tutorial/essential/exceptions/advantages.html |archive-date=2011-10-26 }}</ref> Still another discouraged circumvention is to make all exceptions subclass {{C++|RuntimeException}}.,<ref>{{cite web|url=http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html|title=Unchecked Exceptions – The Controversy (The Java™ Tutorials : Essential Classes : Exceptions)|publisher=Download.oracle.com|archive-url=https://web.archive.org/web/20111117042228/http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html|archive-date=2011-11-17|url-status=live|access-date=2011-12-15}}</ref> thus making the exception unchecked. An encouraged solution is to use a catch-all handler or throws clause but with a specific [[superclass (computer science)|superclass]] of all potentially thrown exceptions rather than the general superclass {{C++|Exception}}. Another encouraged solution is to define and declare exception types that are suitable for the level of abstraction of the called method<ref>Bloch 2001:178 {{cite book | last = Bloch | first = Joshua | year = 2001 | title = Effective Java Programming Language Guide | publisher = Addison-Wesley Professional | isbn = 978-0-201-31005-4 | url-access = registration | url = https://archive.org/details/effectivejavapro00bloc }}</ref> and map lower level exceptions to these types by using [[exception chaining]].
 
=== Similar mechanisms ===
Line 179 ⟶ 201:
The roots of checked exceptions go back to the [[CLU programming language]]'s notion of exception specification.<ref name=Mindview/> A function could raise only exceptions listed in its type, but any leaking exceptions from called functions would automatically be turned into the sole runtime exception, {{code|failure}}, instead of resulting in compile-time error.<ref name="CLU">{{cite journal |last1=Liskov |first1=B.H. |last2=Snyder |first2=A. |title=Exception Handling in CLU |journal=IEEE Transactions on Software Engineering |date=November 1979 |volume=SE-5 |issue=6 |pages=546–558 |doi=10.1109/TSE.1979.230191 |s2cid=15506879 |url=http://csg.csail.mit.edu/CSGArchives/memos/Memo-155-3.pdf |access-date=19 December 2021}}</ref> Later, [[Modula-3]] had a similar feature.<ref>{{cite web |url=http://www1.cs.columbia.edu/graphics/modula3/tutorial/www/m3_23.html#SEC23 |title=Modula-3 - Procedure Types |publisher=.cs.columbia.edu |date=1995-03-08 |access-date=2011-12-15 |url-status=live |archive-url=https://web.archive.org/web/20080509143753/http://www1.cs.columbia.edu/graphics/modula3/tutorial/www/m3_23.html#SEC23 |archive-date=2008-05-09 }}</ref> These features don't include the compile time checking that is central in the concept of checked exceptions.<ref name=Mindview>{{cite web |url=http://www.mindview.net/Etc/Discussions/CheckedExceptions |archive-url=https://web.archive.org/web/20020405175011/http://www.mindview.net/Etc/Discussions/CheckedExceptions |url-status=dead |archive-date=2002-04-05 |title=Bruce Eckel's MindView, Inc: Does Java need Checked Exceptions? |publisher=Mindview.net |access-date=2011-12-15 }}</ref>
 
Early versions of the C++ programming language included an optional mechanism similar to checked exceptions, called '''exception specifications'''. By default any function could throw any exception, but this could be limited by a {{Cpp|throw}} clause (similar to the {{Java|throws}} clause in Java) added to the function signature, that specified which exceptions the function may throw.
Early versions of the C++ programming language included an optional mechanism similar to checked exceptions, called '''exception specifications'''. By default any function could throw any exception, but this could be limited by a {{Cpp|throw}} clause added to the function signature, that specified which exceptions the function may throw. Exception specifications were not enforced at compile-time. Violations resulted in the global function {{Cpp|std::unexpected}} being called.<ref name=bjarne-exc>[[Bjarne Stroustrup]], ''[[The C++ Programming Language]]'' Third Edition, [[Addison Wesley]], 1997. {{ISBN|0-201-88954-4}}. pp. 375-380.</ref> An empty exception specification could be given, which indicated that the function will throw no exception. This was not made the default when exception handling was added to the language because it would have required too much modification of existing code, would have impeded interaction with code written in other languages, and would have tempted programmers into writing too many handlers at the local level.<ref name=bjarne-exc/> Explicit use of empty exception specifications could, however, allow C++ compilers to perform significant code and stack layout optimizations that are precluded when exception handling may take place in a function.<ref name=cppeh /> Some analysts viewed the proper use of exception specifications in C++ as difficult to achieve.<ref>{{cite journal | title=Ten Guidelines for Exception Specifications | last=Reeves | first= J.W. | journal=C++ Report | volume=8 | issue=7 |date=July 1996}}</ref> This use of exception specifications was included in [[C++98]] and [[C++03]], [[deprecated]] in the 2012 C++ language standard ([[C++11]]),<ref>{{cite web |url=http://herbsutter.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ |title=Trip Report: March 2010 ISO C++ Standards Meeting |last=Sutter |first=Herb |author-link=Herb Sutter |date=3 March 2010 |access-date=24 March 2010 |url-status=live |archive-url=https://web.archive.org/web/20100323082634/http://herbsutter.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ |archive-date=23 March 2010 }}</ref> and was removed from the language in [[C++17]]. A function that will not throw any exceptions can now be denoted by the {{Cpp|noexcept}} keyword.
 
<syntaxhighlight lang="C++">
void performSomeOperation(int a, int b) throw(std::invalid_argument, std::domain_error) {
// ...
}
</syntaxhighlight>
 
C++ <code>throw</code> clauses could specify any number of any types, even primitives and classes that did not extend <code>std::exception</code>.
 
Exception specifications were not enforced at compile-time. Violations resulted in the global function {{Cpp|std::unexpected}} being called.<ref name=bjarne-exc>[[Bjarne Stroustrup]], ''[[The C++ Programming Language]]'' Third Edition, [[Addison Wesley]], 1997. {{ISBN|0-201-88954-4}}. pp. 375-380.</ref> An empty exception specification could be given, which indicated that the function will throw no exception. This was not made the default when exception handling was added to the language because it would have required too much modification of existing code, would have impeded interaction with code written in other languages, and would have tempted programmers into writing too many handlers at the local level.<ref name=bjarne-exc/> Explicit use of empty exception specifications could, however, allow C++ compilers to perform significant code and stack layout optimizations that are precluded when exception handling may take place in a function.<ref name=cppeh /> Some analysts viewed the proper use of exception specifications in C++ as difficult to achieve.<ref>{{cite journal | title=Ten Guidelines for Exception Specifications | last=Reeves | first= J.W. | journal=C++ Report | volume=8 | issue=7 |date=July 1996}}</ref> This use of exception specifications was included in [[C++98]] and [[C++03]], [[deprecated]] in the 2012 C++ language standard ([[C++11]]),<ref>{{cite web |url=http://herbsutter.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ |title=Trip Report: March 2010 ISO C++ Standards Meeting |last=Sutter |first=Herb |author-link=Herb Sutter |date=3 March 2010 |access-date=24 March 2010 |url-status=live |archive-url=https://web.archive.org/web/20100323082634/http://herbsutter.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ |archive-date=23 March 2010 }}</ref> and was removed from the language in [[C++17]]. Throws clauses were replaced by {{Cpp|noexcept}} clauses. A function that will not throw any exceptions would now be denoted by the {{Cpp|noexcept}} keyword, and instead {{Cpp|noexcept(false)}} specified that a function will throw. Although <code>throw</code> clauses are removed from the language, writing only <code>throw()</code> in the signature is legal and is equivalent to <code>noexcept</code> (no exception specified by the <code>throw</code> clause denotes that it cannot throw). For transitioning a codebase that uses <code>throw</code> clauses, they can be adapted by instead redefining them with a macro to quickly resolve rejection of the removed <code>throw</code> clause by the compiler.
 
<syntaxhighlight lang="C++">
#define throw(...) noexcept(false)
</syntaxhighlight>
 
One can also specify that a function is <code>noexcept</code> conditionally on another function being <code>noexcept</code>, like so:
 
<syntaxhighlight lang="C++">
void mightThrow();
 
// The first noexcept is the noexcept clause, the second is the noexcept operator which evaluates to a Boolean value
void f() noexcept(noexcept(mightThrow()));
</syntaxhighlight>
 
Though C++ has no checked exceptions, one can propagate the thrown object up the stack when inside a <code>catch</code> block, by writing {{cpp|throw;}} (without specifying an object). This re-throws the caught object. This allows operations to be done within the <code>catch</code> block that catches it, before choosing to allow the object to continue propagating upwards.
 
An uncaught exceptions analyzer exists for the [[OCaml]] programming language.<ref>{{cite web |url=http://caml.inria.fr/pub/old_caml_site/ocamlexc/ocamlexc.htm |title=OcamlExc - An uncaught exceptions analyzer for Objective Caml |publisher=Caml.inria.fr |access-date=2011-12-15 |url-status=live |archive-url=http://archive.wikiwix.com/cache/20110806090555/http://caml.inria.fr/pub/old_caml_site/ocamlexc/ocamlexc.htm |archive-date=2011-08-06 }}</ref> The tool reports the set of raised exceptions as an extended type signature. But, unlike checked exceptions, the tool does not require any syntactic annotations and is external (i.e. it is possible to compile and run a program without having checked the exceptions).
 
In C++, one can also perform "Pokémon exception handling". Like <syntaxhighlight lang="java" inline>catch (Throwable t)</syntaxhighlight> in Java, C++ supports a <syntaxhighlight lang="cpp">catch (...)</syntaxhighlight> block, which will catch any thrown object. However, <code>catch (...)</code> has the disadvantage of not naming the caught object, which means it cannot be referred to.
== Dynamic checking of exceptions ==
 
<syntaxhighlight lang="cpp">
// Catching only exceptions:
try {
// ...
} catch (const std::exception& e) {
// Catching only exceptions:
std::println("An exception was caught: {}", e.what());
} catch (...) {
// Catching all thrown objects:
std::println("An unknown error was caught");
}
</syntaxhighlight>
 
The [[Rust (programming language)|Rust]] language, instead of using exceptions altogether, represents recoverable exceptions as [[result type]]s.<ref>{{cite web |title=std::result - Rust |url=https://doc.rust-lang.org/std/result/index.html |url-status=live |archive-url=https://web.archive.org/web/20231009032955/https://doc.rust-lang.org/std/result/index.html |archive-date=2023-10-09 |access-date=2023-10-09 |website=doc.rust-lang.org}}</ref><ref>{{cite web |date=2011-10-29 |title=stdlib: Add result module · rust-lang/rust@c1092fb |url=https://github.com/rust-lang/rust/commit/c1092fb6d88efe51e42df3aae2a321cc669e12a0 |url-status=live |archive-url=https://web.archive.org/web/20231009033047/https://github.com/rust-lang/rust/commit/c1092fb6d88efe51e42df3aae2a321cc669e12a0 |archive-date=2023-10-09 |access-date=2023-10-09 |website=github.com}}</ref> This is represented as <code>Result<T, E></code> (or <code>expected<T, E></code> in C++). The advantage of result types over checked exceptions is that while both result types and checked exceptions force users to immediately handle errors, they can also be directly represented as a return type within the language's type system, unlike checked exceptions where the declared potentially thrown exception is part of the function signature but not directly part of its return type.
 
== Dynamic checking of exceptions ==
{{unsourcedsection|date=February 2025}}
The point of exception handling routines is to ensure that the code can handle error conditions. In order to establish that exception handling routines are sufficiently robust, it is necessary to present the code with a wide spectrum of invalid or unexpected inputs, such as can be created via software [[fault injection]] and [[mutation testing]] (that is also sometimes referred to as [[fuzz testing]]). One of the most difficult types of software for which to write exception handling routines is protocol software, since a robust protocol implementation must be prepared to receive input that does not comply with the relevant specification(s).
 
Line 192 ⟶ 256:
 
== Asynchronous exceptions ==
'''Asynchronous exceptions''' are events raised by a separate thread or external process, such as pressing [[Control-C|Ctrl-C]] to interrupt a program, receiving a [[Signal (computing)|signal]], or sending a disruptive message such as "stop" or "suspend" from another [[Thread (computer science)|thread of execution]].<ref>{{cite web |url=http://citeseer.ist.psu.edu/415348.html |title=Asynchronous Exceptions in Haskell - Marlow, Jones, Moran (ResearchIndex) |publisher=Citeseer.ist.psu.edu |access-date=2011-12-15 |url-status=live |archive-url=http://archive.wikiwix.com/cache/20110223164151/http://citeseer.ist.psu.edu/415348.html |archive-date=2011-02-23 }}</ref><ref>{{cite journaltech report|url=http://www.cs.williams.edu/~freund/papers/python.pdf |title=Safe Asynchronous Exceptions For Python |access-date=4 January 2022 |first1=Stephen N.|last1=Freund|first2=Mark P.|last2=Mitchell }}</ref> Whereas synchronous exceptions happen at a specific <code>throw</code> statement, asynchronous exceptions can be raised at any time. It follows that asynchronous exception handling can't be optimized out by the compiler, as it cannot prove the absence of asynchronous exceptions. They are also difficult to program with correctly, as asynchronous exceptions must be blocked during cleanup operations to avoid resource leaks.
 
Programming languages typically avoid or restrict asynchronous exception handling, for example C++ forbids raising exceptions from signal handlers, and Java has deprecated the use of its ThreadDeath exception that was used to allow one thread to stop another one.<ref>{{cite web |url=http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html |title=Java Thread Primitive Deprecation |publisher=Java.sun.com |access-date=2011-12-15 |url-status=live |archive-url=https://web.archive.org/web/20090426200153/http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html |archive-date=2009-04-26 }}</ref> Another feature is a semi-asynchronous mechanism that raises an asynchronous exception only during certain operations of the program. For example, Java's {{C++|Thread.interrupt()}} only affects the thread when the thread calls an operation that throws {{C++|InterruptedException}}.<ref>{{cite web |title=Interrupts (The Java™ Tutorials > Essential Java Classes > Concurrency) |url=https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html |website=docs.oracle.com |access-date=5 January 2022}}</ref> The similar POSIX {{C++|pthread_cancel}} API has race conditions which make it impossible to use safely.<ref>{{cite web |last1=Felker |first1=Rich |title=Thread cancellation and resource leaks |url=http://ewontfix.com/2/ |website=ewontfix.com|access-date=5 January 2022}}</ref>
 
== Condition systems ==
[[Common Lisp]], [[R (programming language)|R]],<ref>{{Cite web |title=R: Condition Handling and Recovery |url=https://search.r-project.org/R/refmans/base/html/conditions.html |access-date=2024-03-25 |website=search.r-project.org}}</ref> [[Dylan (programming language)|Dylan]] and [[Smalltalk]] have a [[condition system]]<ref>{{cite web|author = What Conditions (Exceptions) are Really About|url = http://danweinreb.org/blog/what-conditions-exceptions-are-really-about|title = What Conditions (Exceptions) are Really About|publisher = Danweinreb.org|date = 2008-03-24|access-date = 2014-09-18|url-status = deadusurped|archive-url = https://web.archive.org/web/20130201124021/http://danweinreb.org/blog/what-conditions-exceptions-are-really-about|archive-date = February 1, 2013}}</ref> (see [[Common Lisp#Condition system|Common Lisp Condition System]]) that encompasses the aforementioned exception handling systems. In those languages or environments the advent of a condition (a "generalisation of an error" according to [[Kent Pitman]]) implies a function call, and only late in the exception handler the decision to unwind the stack may be taken.
 
Conditions are a generalization of exceptions. When a condition arises, an appropriate condition handler is searched for and selected, in stack order, to handle the condition. Conditions that do not represent errors may safely go unhandled entirely; their only purpose may be to propagate hints or warnings toward the user.<ref>{{cite web |url=httphttps://www.franz.com/support/documentation/611.20/ansicl/section/conditio.htm |title=9.1 Condition System Concepts |publisher=Franz.com |date=20092022-07-2125 |access-date=20112024-1206-1507 |archive-url=https://web.archive.org/web/2007062821322120240607165853/httphttps://www.franz.com/support/documentation/611.20/ansicl/section/conditio.htm |archive-date=20072024-06-2807 |url-status=deadlive }}</ref>
 
=== Continuable exceptions ===
Line 207 ⟶ 271:
 
=== Restarts separate mechanism from policy ===
Condition handling moreover provides a [[separation of mechanism fromand policy]]. Restarts provide various possible mechanisms for recovering from error, but do not select which mechanism is appropriate in a given situation. That is the province of the condition handler, which (since it is located in higher-level code) has access to a broader view.
 
An example: Suppose there is a library function whose purpose is to parse a single [[syslog]] file entry. What should this function do if the entry is malformed? There is no one right answer, because the same library could be deployed in programs for many different purposes. In an interactive log-file browser, the right thing to do might be to return the entry unparsed, so the user can see it—but in an automated log-summarizing program, the right thing to do might be to supply null values for the unreadable fields, but abort with an error, if too many entries have been malformed.
Line 222 ⟶ 286:
 
The [[Go (programming language)#Omissions|Go]] developers believe that the try-catch-finally idiom obfuscates [[control flow]],<ref>{{cite web |url=https://golang.org/doc/faq#exceptions |title=Frequently Asked Questions |access-date=2017-04-27 |quote=We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional. |url-status=live |archive-url=https://web.archive.org/web/20170503205801/https://golang.org/doc/faq#exceptions |archive-date=2017-05-03 }}</ref> and introduced the exception-like {{code|lang=go|panic}}/{{code|lang=go|recover}} mechanism.<ref>[https://code.google.com/p/go-wiki/wiki/PanicAndRecover Panic And Recover] {{webarchive|url=https://web.archive.org/web/20131024144034/https://code.google.com/p/go-wiki/wiki/PanicAndRecover |date=2013-10-24 }}, Go wiki</ref> {{code|lang=go|recover()}} differs from {{code|catch}} in that it can only be called from within a {{code|lang=go|defer}} code block in a function, so the handler can only do clean-up and change the function's return values, and cannot return control to an arbitrary point within the function.<ref>{{cite web |last1=Bendersky |first1=Eli |title=On the uses and misuses of panics in Go |url=https://eli.thegreenplace.net/2018/on-the-uses-and-misuses-of-panics-in-go/ |website=Eli Bendersky's website |access-date=5 January 2022 |date=8 August 2018|quote=The specific limitation is that recover can only be called in a defer code block, which cannot return control to an arbitrary point, but can only do clean-ups and tweak the function's return values. }}</ref> The {{code|lang=go|defer}} block itself functions similarly to a {{code|finally}} clause.
 
The [[Rust (programming language)|Rust]] language does not have exceptions. It instead uses {{code|lang=rust|Result<T, E>}} (a [[result type]]) for handling runtime errors, and for serious errors the {{code|lang=rust|panic!()}} macro is used.
 
==See also==
Line 238 ⟶ 304:
===Works cited===
* {{Cite conference |doi=10.1145/1529966.1529967 |title=A Pattern of Language Evolution |conference=LISP50: Celebrating the 50th Anniversary of Lisp |pages=1–10 |year=2008 |last1=Gabriel |first1=Richard P. |author-link1=Richard P. Gabriel |last2=Steele |first2=Guy L. |author-link2=Guy L. Steele, Jr. |url=http://www.dreamsongs.com/Files/PatternOfLanguageEvolution.pdf |isbn=978-1-60558-383-9}}
* {{Cite conference| doi = 10.1145/512976.512997| title = Structured exception handling| conference = Proceedings of the 2nd ACM SIGACT-SIGPLAN symposium on Principles of programming languages - POPL '75| pages = 204–224| date = 1975a<!-- See other paper at: [[Template:Cite doi/10.1145.2F361227.361230]] -->| last = Goodenough | first = John B.<!-- not the physicist -->}}
* {{Cite journal| doi = 10.1145/361227.361230| title = Exception handling: Issues and a proposed notation| url = http://www.cs.colorado.edu/~bec/courses/csci5535-s09/reading/goodenough-exceptions.pdf| journal = Communications of the ACM| volume = 18| issue = 12| pages = 683–696| year = 1975| last = Goodenough | first = John B.<!-- not the physicist -->| ref = {{harvid|Goodenough|1975|b}}<!-- See other paper at: [[Template:Cite doi/10.1145.2F512976.512997]] -->| citeseerx = 10.1.1.122.7791| s2cid = 12935051}}
* {{cite book |last1=Stroustrup |first1=Bjarne |title=The design and evolution of C++ |date=1994 |publisher=Addison-Wesley |___location=Reading, Mass. |isbn=0-201-54330-3 |edition=1st}}
* {{cite conference |first=Jon L<!-- no period --> |last=White |title=NIL - A Perspective |date=May 1979 |conference=Proceedings of the 1979 Macsyma User's Conference |url=http://www.softwarepreservation.org/projects/LISP/MIT/White-NIL_A_Perspective-1979.pdf}}