Note that this isn't a full discussion; there are several
important rationale that aren't contained here. It does, however, present
one rationale quite well (certainly better than I have...), and I think it's
worthwhile to post it, even in an incomplete form.
------------------------------------------------------------------
Why doesn't C# require exception specifications?
------------------------------------------------------------------
Some languages allow or require member signatures to include
exception specifications. E.g., in C++, a method that raises an
ArgumentException can be declared with:
void F(int a) throw (MyException) {...}
and in Java such a method can be defined as
void F(int a) throws MyException {...}
C# neither requires nor allows such exception
specifications. Examination of small programs leads to the conclusion that
requiring exception specifications could both enhance developer productivity
and enhance code quality, but experience with large software projects
suggests a different result -- decreased productivity and little or no
increase in code quality.
Requiring exception specifications would decrease developer
productivity because of the sheer proliferation of exception specifications.
This proliferation proceeds in two dimensions:
The number of members. Modern exception handling allows a
division of work between the code that raises the exception and the code
that handles it. These pieces of code may be separated by intervening code.
E.g., A calls B, B calls C, C calls D, and D raises an exception that is
eventually handled by A. If C# required exception specifications, then each
of A, B, C, and D would have to contain exception-handling related code even
though only A and D do any actual work related to the exception.
The number of possible exceptions. The number of exceptions
is unquestionably large. E.g., any code that adds two numbers could result
in an overflow exception, any code that divides two numbers could result in
a divide by zero exception, and any code that instantiates an object could
result in an out of memory exception.
The lack of an increase in code quality is related to the
response of developers to the proliferation of exception specifications.
Developers who carefully examine all of the exception specification errors
reported by the compiler might see an increase in code quality, but this
would come at the expense of productivity. On the other hand, some
developers will respond to the errors by mindlessly adding whatever
exception specifications the compiler requires, and others will choose to
subvert the intent of the language designers by adding a generic exception
specification to every member. The former option is unlikely to increase
code quality. The latter option effectively makes exception specifications
optional -- every member is required to have a "throws Exception" clause but
this doesn't actually communicate any information or require any thought.
A better strategy is for client code -- code that is using a
class library -- to include both generic exception handling and specific
exception handling. Generic exception handling is performed centrally, and
generically deals with all exceptions. Specific exception handling checks
for a smaller number of exceptions -- the ones that the client code is
specifically prepared to respond to or recover from. This split between
generic and specific exception handlers is practically required since some
exceptions (e.g., out of memory exceptions) can occur in many program
locations but are rare in frequency. All client code needs to have some
generic exception handling.
It is interesting to note that neither Java nor C++ is
strict about requiring exception specifications:
Java provides support for both checked and unchecked
exceptions, and (in a "do as I say and not as I do" wrinkle) many of the
Java-defined exceptions are unchecked exceptions. A class author is
supposed to judge whether the exception can occur "at many points in the
program" and whether "recovery would be difficult or impossible" in order to
make a decision about whether to employ a checked or unchecked exception.
We think that this is an impossible decision to make since these factors are
highly dependent on the code that is using the class rather than the class
itself.
The C++ language standard requires struct exception
checking, but this standard is commonly ignored by tools, including Visual
C++. Given the proliferation of exception specifications (see above) and
the lack of compiler enforcement, it is hard to imagine that a complex class
library could actually get the exception specifications right. If the
exceptions are "just for documentation purposes" then we think they belong
in the documentation rather than the code.
Which leads me to the documentation question. The class
library documentation is automatically generated from C#'s XML-based
in-source documentation. For instance, the code below can be compiled with
the /doc option to produce an accompanying XML file. Here's the code:
using System;
class Test
{
/// <summary>
/// The F method does not do anything interesting.
/// </summary>
/// <param name="x">the value to F</param>
/// <exception type="cref=ArgumentException">If the
argument is negative.</exception>
static void F(int x) {
if (x < 0)
throw new ArgumentException();
Console.WriteLine("F({0})", x);
}
static void Main(string[] args) {
try {
F(0);
F(-1);
}
catch(ArgumentException) {
Console.WriteLine("ArgumentException");
}
}
}
Here is the accompanying XML file that is generated:
<?xml version="1.0"?>
<doc>
<assembly>
<name>scratch</name>
</assembly>
<members>
<member name="M:Test.F(System.Int32)">
<summary>
The F method does not do anything interesting.
</summary>
<param name="x">the value to F</param>
<exception type="cref=ArgumentException">If the
argument is negative.</exception>
</member>
</members>
</doc>
We then use the generated file to automatically produce
documentation.
You can read messages from the DOTNET archive, unsubscribe from DOTNET, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.