Checked Exceptions!

  • Thread starter Thread starter OvErboRed
  • Start date Start date
O

OvErboRed

I just read a whole bunch of threads on microsoft.public.dotnet.* regarding
checked exceptions (the longest-running of which seems to be <cJQQ9.4419
[email protected]>.

My personal belief is that checked exceptions should be required in .NET. I
find that many others share the same views as I do. It is extremely
frustrating to have to work around this with hacks like Abstract ADO.NET
and CLRxLint (which still don't solve the problem).

On the other hand, it seems that most of the @microsoft.com posters are
ignoring or adamantly refusing to accept the argument (and fact) that
exception specification is as essential as parameter and return type
specification when it comes to creating well-defined interfaces.

I'm wondering if there's any hope at all for MS to introduce checked
exceptions into an upcoming iteration of .NET. What would it take to move
MS to action (or at least more serious consideration) on such issues as
this? I realize that at this point, a shift at such a fundamental level
will not be easy, but perhaps this will be something to look forward to in
..NET 2.
 
Fully agree to your views on checked exceptions. I program in Java also and
really appreciate this notion
 
It would be a good thing, especially if the people you work with don't check
for exceptions, or much else of anything...
 
Trouble is that this can break components that rely on functions that
specify what exceptions they throw.

For instance, if MusicPlayer.exe uses a function PlayMusic() in
MusicPlayer.dll and PlayMusic is changed and now can throw a IOException,
unless MusicPlayer.exe is completely recompiled the code will break. Sorry
for the simplistic explanation but its beginning to get late! :)

I think thats what someone from MS said a while ago neway. I agree that it
is useful, maybe just a check at compile time or in debug builds or
something?

Hope this helps
Kieran
 
I'd settle for accurate exception specifications in the documentation! I
can't count the number of times I still get unhandled exceptions in code
that catches every documented exception.
 
Another issue is the runtime performance cost involved with checked
exceptions.

-Andre
 
Managed code itself has a runtime performance hit as well, but the
protections it provides make it well worth it. I think of checked
exceptions similarly. Newer hardware can always take care of that :)
 
Andre said:
Another issue is the runtime performance cost involved with checked
exceptions.

Checked exceptions are (or at least can be) checked at compile time
rather than runtime. Why should it have any performance implications at
runtime?

If the runtime were required to check that only the declared checked
exceptions could be thrown, that would create a slight performance cost
at runtime when loading the type/method, but needn't create any other
cost as far as I can see.
 
How about a third alternative...

A compiler could examine all the exceptions thrown from a method and bake
the data of the exception types thrown directly into the metadata of the
method. Tools could then examine this and use it as they see fit.

One example of how this could be used is to use auto-completion to provide
catch blocks for some or all of the known exceptions thrown within a scope.

Regardless of how tools could use this data the advantage is that it is not
required and it is backwardly compatible with all existing assemblies. If
the data is not present then the tools would find zero exceptions thrown; as
assemblies get updated by tools that understand the new metadata, it would
automatically get put into them. Also, since the data is generated each time
the assembly is compiled it avoids the problem of the documentation not
matching the code, and it avoids a runtime hit.

DaveL
 
We are working to make the information about what exceptions could happen
more available.

In many cases, however, you can't derive it directly from code, because
you're operating through interfaces, and you don't know at compile time what
object is implementing them. Dynamic create of objects has the same problem,
as does factory methods that return a base class.

--
Eric Gunnerson

Visit the C# product team at http://www.csharp.net
Eric's blog is at http://blogs.gotdotnet.com/ericgu/

This posting is provided "AS IS" with no warranties, and confers no rights.
 
I think there are a couple of important considerations here.

The first is whether checked exceptions are a good idea in principle.
There are lots of different opinions here - some people think that
checked exceptions are essential, some think that checked exceptions
are good but should be used in conjunction with unchecked exceptions,
and some think that checked exceptions cause more problems than they
solve. For view against checked exceptions from the Java (and C++)
world, I suggest looking at Bruce Eckel's position at
http://www.mindview.net/Etc/Discussions/CheckedExceptions.

You reference this paper frequently. Eckel's arguments are entirely
psychological. In fact, from a theoretical view, he readily concedes the
merits of checked exceptions. Rather, his points are based on the
developer's practical tendency to ignore exceptions in code that is
under construction.

Java provides you with an opt-out model:

....
} catch (SomeKindOfException e) {}

From his perspective, this is bad, because it slows down lazy
programmers, or at least those "you might classify as beginners." That,
really, is the gist of his article.

I don't know about you, but frankly, I don't find this to be a very
sound argument for the exclusion of a feature that effectively *forces*
all developers to put up with a lax policy. In Java, less-scrupulous
programmers had the freedom to swallow exceptions or to add "throws
Exception" to their method signatures.
The second is what it would actually mean to implement checked
exceptions on the .NET platform. There are two ways you could do it.

You could implement checked exceptions in C# only, but using libraries
written in other languages would be strange, in that they would not
have exception information. This probably would not work very well.

The second option would be to implement checked exceptions throughout
.NET. That would mean that all languages would be required to support
checked exceptions. I think it's fair to say that if Microsoft took
that position, it would not be a popular one amongst the language
implementors, both inside and outside of Microsoft. We've tried to
limit the requirements we impose on other languages as much as
practical, and checked exceptions would be a bit imposition.

I'm not entirely sure what you mean; I would think that the addition of
checked exceptions would hardly be any more significant a burden than
those already associated with reaching CLS compliance.

And even if such requirements demand extra effort of the language
implementors, the resulting benefits of static type checking would go a
long way in aiding the rest (the majority) of the .NET developer
community.
Because of these considerations, checked exceptions are an issue where
we can't satisfy all of our users. We will continue to explore the
issue in the future.

From your previous posts, I realize your concern with flexibility (e.g.,
the ability to throw SpecializedDatabaseException when connecting to a
DB), but this type of thinking is misguided. First of all, the issue is
already addressed in .NET with exception chaining/tunneling. Secondly,
if you seek true flexibility, there's always C/C++. C/C++, where
exceptions are thrown unchecked, pointers can reference any gosh-durned
location, and type casting knows no bounds.

But that sort of flexibility is not what .NET is about, is it? It's the
simplified abstractions and the higher level features of a clean, new
platform that attract programmers and make their lives easier. To omit
exception checking from this feature set is a critical mistake, and it
is unfortunate that Microsoft chose this path initially, but I implore
you to rectify the situation when the opportunity next presents itself.
 
We are working to make the information about what exceptions could
happen more available.

In many cases, however, you can't derive it directly from code, because
you're operating through interfaces, and you don't know at compile time
what object is implementing them. Dynamic create of objects has the same
problem, as does factory methods that return a base class.

While I think checked exceptions shouldn't be in a language
definition, to solve the problem you describe above, you could allow
exception definitions (if you go the checked exception route) in the
interface definition's method definitions, which then simply says: if
someone implements this method, it should throw this and this exception.

Which in itself is a reason not to use checked exceptions, because
what if the implementation of the method doesn't require to throw one or
two of these exceptions?

FB
 
Frans Bouma said:
While I think checked exceptions shouldn't be in a language
definition, to solve the problem you describe above, you could allow
exception definitions (if you go the checked exception route) in the
interface definition's method definitions, which then simply says: if
someone implements this method, it should throw this and this exception.

Which in itself is a reason not to use checked exceptions, because
what if the implementation of the method doesn't require to throw one or
two of these exceptions?

Then the implementation doesn't declare that it can throw the
exception, and if the caller *knows* which implementation is being used
(and has a reference of that type rather than just the interface type)
then they won't have to catch/pass on that exception.

For an example of this (in abstract classes rather than interfaces, but
it's the same principal) in Java, look at OutputStream.write(int) and
PrintStream.write(int).

Basically an implementation/override can declare that it throws fewer
exceptions, but not more.
 
Then the implementation doesn't declare that it can throw the
exception, and if the caller *knows* which implementation is being used
(and has a reference of that type rather than just the interface type)
then they won't have to catch/pass on that exception.

For an example of this (in abstract classes rather than interfaces, but
it's the same principal) in Java, look at OutputStream.write(int) and
PrintStream.write(int).

Basically an implementation/override can declare that it throws fewer
exceptions, but not more.

Ok, but doesn't an interface implicate a fixed definition? So if an
implementator decides not to throw a given exception, does that
implementator in fact not implement the complete interface? It looks like
Sun cut a corner on this :)

FB
 
Frans Bouma said:
Ok, but doesn't an interface implicate a fixed definition? So if an
implementator decides not to throw a given exception, does that
implementator in fact not implement the complete interface? It looks like
Sun cut a corner on this :)

No, not at all. The interface says what you should do if a certain type
of thing does wrong. If that kind of thing can't possibly go wrong in
your implementation, then there's no need to redeclare that.

It's basically the Liskov Substitutability Principle again - the
interface says, "If you've got something that implements this
interface, you can call this method and expect a certain result if a
certain thing goes wrong" - and the implementation where that certain
thing can't go wrong is still abiding by that interface.
 
Jon Skeet said:
No, not at all. The interface says what you should do if a certain type
of thing does wrong. If that kind of thing can't possibly go wrong in
your implementation, then there's no need to redeclare that.

It's basically the Liskov Substitutability Principle again - the
interface says, "If you've got something that implements this
interface, you can call this method and expect a certain result if a
certain thing goes wrong" - and the implementation where that certain
thing can't go wrong is still abiding by that interface.

--

This approach should work but it begs the question of whether an exception
specification in an interface is a useful feature to have. I am not
convinced that adding it to an interface definition yields the expected
benefits because a real-world implementation may have many more exception
types to deal with then the designer of the interface ever expected.

I see the value in some flavor of checked exceptions as a design-time aid
rather then a runtime requirement.

There is a benefit for tools to be capable to tracing the exception graph of
an object. At design time when using a given type I am concerned about what
it might do so that I can write code to correctly handle the exception. I
want the exception information to be available to me (through intellisense)
for the same reason I want to know the arguments to a method. I think this
would work well when dealing with concrete types; it works less well with
late-bound types where the actual type or instance is not known until
runtime, as typically occurs when using reflection against a type or an
interface.


I'd rather not have any information then have incorrect information and
relying on interface specifications creates the problem of the documentation
not matching the code. I think the feature is most useful when the language
compiler can automatically generate the information at the time the type or
interface is compiled into IL. I believe it less useful to rely on interface
declarations as this can get out-of-date and be mismatched very easily - the
number of ways to get this wrong is larger then the number of ways to get it
right. It's easy to do on small projects, but on large projects (where the
feature adds the most benefits) it's harder to maintain.

Computers are good at automating repetitive tasks; detecting exceptions that
can be thrown from a given implementation falls into this category.

Note to designers of future languages - the existence of this debate is a
clue that this aspect of programming needs a lot of thought. I have yet to
see a language and runtime implementation that solves the general error
handling problem correctly and consistently. We've come a long way from the
"System error 42" days but there's a lot more work that needs to be done.

Dave
 
Dave said:
This approach should work but it begs the question of whether an exception
specification in an interface is a useful feature to have. I am not
convinced that adding it to an interface definition yields the expected
benefits because a real-world implementation may have many more exception
types to deal with then the designer of the interface ever expected.

Most of the time, it works very well, in my experience. The interface
designer needs to be careful, of course, but they should include
exceptions which match what was meant to happen, and allow exception
chaining to give specific exceptions. For instance, when performing
some database operation, it makes sense for a SqlException to be thrown
even if underlying that there was an IOException (which is then chained
onto the SqlException).

Where it becomes a little messier is where there will *always* be a
chained exception, and the original exception is virtually never
meaningful in itself - for instance, if an iterator had an
IterationException, it would usually be because something underneath
had caused a problem.

Having used both Java and C# fairly extensively now, I can see how not
having checked exceptions makes the C# coding quicker - particularly
when you're writing quick test code rather than production code - but I
still think the Java approach prods the developer to consider possibly
error routes more.
 
No, not at all. The interface says what you should do if a certain type
of thing does wrong. If that kind of thing can't possibly go wrong in
your implementation, then there's no need to redeclare that.

that's for the caller/user of the interface. What about the
developer of the code which implements the interface? That developer now
has to implement all described functionality (logically), however what
would/should/does the compiler do when that developer doesn't throw an
exception defined in such interface? The compiler barfs when a method is
not implemented, however does it also cough up an error if a given
exception is not implemented?

Also, if the developer of the implementation DOESN'T throw any of
the exceptions specified but another one, how would the code using the
interface gain anything? The interface clearly doesn't describe the
reality. (and thus makes the whole purpose, although nice to have,
useless)

FB
 
Frans Bouma said:
that's for the caller/user of the interface. What about the
developer of the code which implements the interface? That developer now
has to implement all described functionality (logically), however what
would/should/does the compiler do when that developer doesn't throw an
exception defined in such interface? The compiler barfs when a method is
not implemented, however does it also cough up an error if a given
exception is not implemented?

No - because the only reason for not throwing the exception is if the
condition under which the interface says the exception should be thrown
doesn't/can't happen.
Also, if the developer of the implementation DOESN'T throw any of
the exceptions specified but another one, how would the code using the
interface gain anything? The interface clearly doesn't describe the
reality. (and thus makes the whole purpose, although nice to have,
useless)

You're putting up a straw man here of the developer being pretty much
deliberately irresponsible. The interface should describe sufficiently
general exceptions so that anything that can go wrong can be mapped to
one of the exceptions, often including chaining (so that even if the
cause isn't immediately as described, it is the same type of thing).
The developer then obeys the interface by throwing the appropriate
exception, possibly chaining a more fundamental one.

For instance, in a database implemented directly over a file system, if
an IO error occurred when reading a file, you'd still throw a database-
type exception (as that's what the caller is dealing with), chained to
an IOException (as that's what the nitty-gritty of what went wrong is
about).
 
Frans Bouma said:
Checked exceptions are in theory a nice idea,

I find checked exceptions awful in theory too !
Checked exceptions abuse the exception mechanism by using it (basically)
instead of return values

They tie the *caller* to a contract, destroying the basic purpose of why we
have structured exceptions in the first place.

While exceptions can trace the stack for a handler without limitations (many
levels), checked exceptions enforce a first level resolution always.

I wonder who invented them ?
 
Back
Top