UPDATED: Rethrows Clause
Reinier Zwitserloot
reinier at zwitserloot.com
Tue May 19 23:46:26 PDT 2009
Here's a trivially simple change to implement, though it has some far
reaching repercussions for java as a whole:
change the 'rethrows' clause to an ignores clause: Any checked
exception in the ignores list may be thrown from the method body, but
is NOT part of the method's checked exception list. It is hence also
not part of the signature, just like sticking a 'synchronized' keyword
on a method isn't part of its signature, but an implementation detail.
example:
Runnable r = new Runnable() {
public void run() ignores UnsupportedEncodingException {
String x = new String(inBytes, "UTF-8");
}
};
This sounds like blowing up the entire point of checked exceptions,
but with java moving towards more interoperation with other JVM based
languages, which almost always throw checked exceptions without
actually declaring them (Jython, JRuby, Scala -- I can't think of a
single one other than java itself that has the notion of checked
exceptions in the first place). If the whole 'java is like the
assembler of the JVM' story is going to hold water, something like
this is needed.
For some further support: I doubt anyone seriously holds the position
that java's checked exception experiment was an unmitigated success.
There are pain points, here and there. The above example in fact
includes two of them: The fact that runnable throws no checked
exceptions is clearly a mistake in regards to threading, because
Thread objects clearly should handle ANY exception falling out of its
run() method (and it in fact does, via the unchecked exception handler
mechanism), and there's a general mismatch between main(), which MAY
throw exceptions, and run(), which may not, even though they are both
'thread start points'. Another mistake is
UnsupportedEncodingExceptions, a checked exception, resulting from a
call to converting byte arrays to strings using an encoding that is
guaranteed by the JVM using a string literal, such as "UTF-8". The
appropriate exception would be UnsupportedEncodingError("This JVM is
broken. Charset UTF-8 missing. Reinstall it") - which is unchecked.
In other words, while I'm not ready to write off checked exceptions as
a whole, I am more than ready to acknowledge that the programmer more
often knows better than the compiler, compared to how often the
programmer, in laziness or inexperience, abuses this freedom.
Especially considering that, on the JVM, you really DONT get checked
exceptions guarantees; any class compiled by anything other than javac
is free to throw checked exceptions without declaring them, and even
in javac you can technically do this using 'sneaky throw' libraries,
which use various workarounds, one of which will NEVER go away*. We're
not losing much here, in other words. In fact, the way javac works,
inexperienced java programmers may erroneously assume that checked
exceptions couldn't possibly happen unless the checked exception is
declared. This is not the case.
*) The one that will never go away is java.lang.Class.newInstance(),
which is functionally defined to sneakily throw on any exceptions
thrown by the constructor, checked or not, and does NOT wrap them up
into a wrapper the way java.lang.reflect.Method.invoke() does. This
cannot change without breaking backwards compatibility. Another one
that will never go away is constructing a class on the fly that sneaky
throws, loading it with ClassLoader's load from bytes mechanism, and
executing it.
Attempting to solve this issue with a library requires rather a lot of
ugly boilerplate:
import static Utils.sneakyThrow;
Runnable r = new Runnable() {
public void run() {
String x;
try {
x = new String(inBytes, "UTF-8");
} catch ( UnsupportedEncodingException e ) {
sneakyThrow(e);
}
}
};
NB: For sanity purposes, the restriction on javac that the try block
MUST contain at least 1 statement that could throw a checked exception
type that is listed on one of the accompanying catch blocks (other
than Exception, which you can always catch), should go away; this has
already been proposed before, and in fact is a backwards compatibility
painpoint for the coin proposal that allows you to rethrow a final
Exception as if its type is the intersection of all checked types
thrown by the statements in the try body.
--Reinier Zwitserloot
Like it? Tip it!
http://tipit.to
On May 20, 2009, at 02:22, Mark Mahieu wrote:
> Yeah, I suppose I did make it rather more complicated than it needed
> to be.
>
> Thanks for the feedback.
>
> Mark
>
>
> On 19 May 2009, at 23:59, Joe Darcy wrote:
>
>> Hello.
>>
>> Hmm; this strikes me as a bit involved for the potential benefits
>> of the feature.
>>
>> -Joe
>>
>> On 03/30/09 05:04 PM, Mark Mahieu wrote:
>>> Forgot my JLS references in the first one...
>>>
>>>
>>>
>>> HTML version + prototype available at:
>>>
>>> http://slm888.com
>>>
>>>
>>>
>>>
>>> Rethrows Clause
>>> v0.1.1
>>>
>>>
>>> AUTHOR(S):
>>>
>>> Mark Mahieu
>>>
>>>
>>> OVERVIEW
>>>
>>> FEATURE SUMMARY: Should be suitable as a summary in a language
>>> tutorial.
>>>
>>> A new clause on method declarations which allows exception
>>> translations (wrapping and rethrowing as a different type) to be
>>> cleanly defined separately from the body of the method. In many
>>> cases, checked exception type names do not then need to be
>>> repeated in a method's throws clause and in a throw statement in
>>> the method body.
>>>
>>>
>>> MAJOR ADVANTAGE: What makes the proposal a favorable change?
>>>
>>> The proposal adds direct support for a common idiom in daily use
>>> by Java programmers worldwide, allowing them to express their
>>> intentions with greater clarity and ease. In comparison with
>>> some proposals, this is an attempt to make dealing with checked
>>> exceptions easier by increasing the expressiveness of exception
>>> handling code in general, rather than by attempting to deprecate
>>> checked exceptions in favour of unchecked exceptions.
>>>
>>>
>>> MAJOR BENEFIT: Why is the platform better if the proposal is
>>> adopted?
>>>
>>> There is a reduction in the amount of boilerplate Java
>>> programmers have to read and write for code dealing with checked
>>> exceptions. Declarations specifying both thrown and rethrown
>>> (wrapped) exceptions are kept together, aiding comprehension of
>>> the code.
>>>
>>>
>>> MAJOR DISADVANTAGE: There is always a cost.
>>>
>>> As with any syntax sugar which enables an alternative way of
>>> expressing an existing idiom, programmers may be tempted to use
>>> it even when the existing idiom would be more appropriate.
>>>
>>>
>>> ALTERNATIVES: Can the benefits and advantages be had some way
>>> without a language change?
>>>
>>> No.
>>>
>>>
>>> EXAMPLES
>>>
>>> SIMPLE EXAMPLE: Show the simplest possible program utilizing the
>>> new feature.
>>>
>>>
>>> Before:
>>>
>>> void before() throws ConfigException {
>>> try {
>>> Class.forName("where.is.the.Code");
>>> }
>>> catch (ClassNotFoundException e) {
>>> throw new ConfigException(e);
>>> }
>>> }
>>>
>>> After:
>>>
>>> void after()
>>> catch ClassNotFoundException throw ConfigException {
>>>
>>> Class.forName("here.is.the.Code");
>>> }
>>>
>>>
>>> ADVANCED EXAMPLE: Show advanced usage(s) of the feature.
>>>
>>> Before:
>>>
>>> void suspendAccount()
>>> throws AuthorizationException,
>>> PersistenceException {
>>> try {
>>> checkMyAuthoritah();
>>> db.update(/*...*/);
>>> log.recordInfo(/*...*/);
>>> }
>>> catch (InfernalDBException e) {
>>> throw new PersistenceException(e);
>>> }
>>> catch (InfernalLogException e) {
>>> throw new RuntimeException(e);
>>> }
>>> }
>>>
>>> After:
>>>
>>> void suspendAccount()
>>> throws AuthorizationException
>>> catch InfernalDBException throw PersistenceException,
>>> InfernalLogException throw RuntimeException {
>>>
>>> checkMyAuthoritah();
>>> db.update(/*...*/);
>>> log.recordInfo(/*...*/);
>>> }
>>>
>>>
>>> DETAILS
>>>
>>> SPECIFICATION: Describe how the proposal affects the grammar,
>>> type system, and meaning of expressions and statements in the
>>> Java Programming Language as well as any other known impacts.
>>>
>>> The syntactic grammar is modified to allow an optional rethrows
>>> clause immediately prior to a MethodBody:
>>>
>>> MethodDeclaratorRest:
>>> FormalParameters {[]} [throws
>>> QualifiedIdentifierList] ( ( [catch ExceptionTranslationList]
>>> MethodBody ) | ; )
>>>
>>> ExceptionTranslationList:
>>> QualifiedIdentifier throw QualifiedIdentifier
>>> { , ExceptionTranslationList }
>>>
>>>
>>>
>>> JLSv3 §8.4.6 : A rethrows clause lists one or more exception
>>> translations, each translation consisting of a caught type C and
>>> a translated type T for which all of the following must hold:
>>> * C <: java.lang.Exception
>>> * T < java.lang.Throwable
>>> * Neither C nor T is a type variable.
>>> * T has an accessible constructor suitable for rethrowing a
>>> value of type C (see below).
>>> * T is not the same type as C.
>>>
>>> Any exceptions thrown by the method body which are a subtype of a
>>> caught exception type in the rethrows clause, are rethrown as the
>>> corresponding translated exception type.
>>>
>>> For a given translated type T with corresponding caught type C, if
>>> T has an accessible constructor accepting a value of type C, then
>>> the translation is equivalent to the following:
>>>
>>> catch (C e) {
>>> throw new T(e);
>>> }
>>>
>>> Otherwise it must have an accessible no argument constructor, and
>>> the translation is equivalent to:
>>>
>>> catch (C e) {
>>> throw new T().initCause(e);
>>> }
>>>
>>>
>>> A rethrows clause does not restrict which types may appear in a
>>> throws clause for the same method. In particular, for a given
>>> caught type C in the rethrows clause, it is permitted for some
>>> type C1 :> C to also be listed in the throws clause.
>>>
>>>
>>> JLSv3 §8.2 : The set of exception types declared to be thrown by
>>> a method is the union of:
>>> * the types in the throws clause
>>> * the translated types in the rethrow clause
>>> * the types thrown by the translated types' selected
>>> constructors
>>>
>>> JLSv3 §11.2.2 : For the purposes of exception analysis, the set
>>> of checked exception types which may be thrown by the method's
>>> body is the union of:
>>> * the types in the throws clause
>>> * the caught types in the rethrows clause
>>>
>>> JLSv3 §11.2.3 : It is a compile-time error if a rethrows clause
>>> contains a translation from a checked exception type C but there
>>> exists no checked exception type E such that all of the following
>>> hold:
>>> * E <: C
>>> * The method body can throw E
>>> * No preceding translation in the rethrow clause catches E or
>>> a supertype of E
>>> unless C is the class java.lang.Exception.
>>>
>>> JLSv3 §13.4.21 : Changes to the rethrows clause of methods or
>>> constructors do not break compatibility with existing binaries;
>>> these clauses are checked only at compile time.
>>>
>>>
>>>
>>> COMPILATION: How would the feature be compiled to class files?
>>> Show how the simple and advanced examples would be compiled.
>>> Compilation can be expressed as at least one of a desugaring to
>>> existing source constructs and a translation down to bytecode. If
>>> a new bytecode is used or the semantics of an existing bytecode
>>> are changed, describe those changes, including how they impact
>>> verification. Also discuss any new class file attributes that are
>>> introduced. Note that there are many downstream tools that
>>> consume class files and that they may to be updated to support
>>> the proposal!
>>>
>>> A simple desugaring could consist of enclosing the method body's
>>> statements in a try statement, with catch clauses for each
>>> translated exception type. For example, the following method:
>>>
>>> Method findMethod()
>>> catch ClassNotFoundException throw ConfigException,
>>> NoSuchMethodException throw ConfigException {
>>>
>>> Class<?> c = Class.forName("some.Thing");
>>> return c.getDeclaredMethod("execute", null);
>>> }
>>>
>>> would be desugared to:
>>>
>>> Method findMethod()
>>> throws ConfigException {
>>> try {
>>> Class<?> c = Class.forName("some.Thing");
>>> return c.getDeclaredMethod("execute", null);
>>> }
>>> catch (ClassNotFoundException e) {
>>> throw new ConfigException(e);
>>> }
>>> catch (MethodNotFoundException e) {
>>> throw new ConfigException(e);
>>> }
>>> }
>>>
>>> No changes to the classfile format are required.
>>>
>>>
>>> TESTING: How can the feature be tested?
>>>
>>> An initial set of jtreg tests is included in the prototype.
>>>
>>>
>>> LIBRARY SUPPORT: Are any supporting libraries needed for the
>>> feature?
>>>
>>> No
>>>
>>>
>>> REFLECTIVE APIS: Do any of the various and sundry reflection APIs
>>> need to be updated? This list of reflective APIs includes but is
>>> not limited to core reflection (java.lang.Class and
>>> java.lang.reflect.*), javax.lang.model.*, the doclet API, and JPDA.
>>>
>>> com.sun.source.tree.MethodTree would require updates to access
>>> the rethrows clause's caught and translated types.
>>>
>>>
>>> OTHER CHANGES: Do any other parts of the platform need be updated
>>> too? Possibilities include but are not limited to JNI,
>>> serialization, and output of the javadoc tool.
>>>
>>> No
>>>
>>>
>>> MIGRATION: Sketch how a code base could be converted, manually or
>>> automatically, to use the new feature.
>>>
>>> Catch clauses which simply wrap and rethrow an exception as
>>> another exception type not caught in an enclosing scope, can be
>>> trivially replaced with a rethrows clause, either manually or
>>> automatically.
>>>
>>> It should be possible for tools to offer bidirectional
>>> conversions such that an exception translation may be moved back
>>> into the method body if it is subsequently decided that
>>> additional logic is required.
>>>
>>>
>>> COMPATIBILITY
>>>
>>> BREAKING CHANGES: Are any previously valid programs now invalid?
>>> If so, list one.
>>>
>>> No
>>>
>>>
>>> EXISTING PROGRAMS: How do source and class files of earlier
>>> platform versions interact with the feature? Can any new
>>> overloadings occur? Can any new overriding occur?
>>>
>>> The semantics of existing class files and legal source files are
>>> unchanged by this feature.
>>>
>>>
>>> REFERENCES
>>>
>>> EXISTING BUGS: Please include a list of any existing Sun bug ids
>>> related to this proposal.
>>>
>>> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6534270
>>> (similar, but emphasizes unchecked exceptions)
>>>
>>>
>>> URL FOR PROTOTYPE (optional):
>>>
>>> http://slm888.com/javac
>>>
>>>
>>>
>>
>
>
More information about the coin-dev
mailing list