Exception transparency - lone throws (no checked exceptions)
Brian Goetz
brian.goetz at oracle.com
Fri Jun 11 10:59:26 PDT 2010
I think this is an interesting exploration of the design space, so I
appreciate your posting it here. However, as several other posters here have
suggested, this isn't really "exception transparency" as much as it is a
limited form of "turn off checked exceptions." (This is a solution to the
problem of exception transparency much as arson is a solution to the problem
of cockroaches.)
Besides the points raised here, I could easily imagine a world where
developers who don't like checked exception just decorated every method with
"throws". I don't know if that is the intent of the proposal or simply a
side-effect, but it is (in our view) some pretty serious collateral damage.
(People are free to argue that they don't like checked exceptions and they
should be abolished. But not here; there are plenty of other fora where such
discussions can happen.)
On 6/10/2010 8:57 AM, Stephen Colebourne wrote:
> I wanted to write up this possible alternative to exception
> transparency - "lone throws". This is a relatively informal
> description for now to express the concept.
>
> Proposal
> --------------------
> This is a simple proposal to permit a new form of throws clause on a
> method definition. The syntax is "throws" with no exception type
> ("lone throws"). For example:
>
> interface Block<T> {
> public void invoke(T element) throws;
> }
>
> A method using this syntax is permitted to throw any Throwable without
> declaring which explicitly:
>
> class MyBlock implements Block<String> {
> public void invoke(String element) throws {
> new File(element).getCanonicalFile().delete();
> }
> }
>
> In the example, the code can throw IOException, but we don't declare
> it in the method signature - just the fact that the method can throw
> anything (checked or unchecked).
>
> On the receiving side, the compiler rules for exception catching are
> changed such that if the total set of exception types that a block of
> code can throw includes "lone throws", then the compiler will permit
> any checked exception to be caught in the catch block:
>
> try {
> MyBlock b = new MyBlock();
> b.invoke("C:\README.txt");
> } catch (IOException ex) {
> ...
> }
>
> In the example, the IOException can be caught, because the invoke
> method declares "lone throws" (normally it can't be caught unless the
> block declares it actually throws IOException)
>
> Extending this to lambdas, I propose that all function types
> implicitly specify "lone throws":
>
> #void(String)
>
> This example is equivalent to the Block interface above - the "lone
> throws" is implied.
>
> Here is the forEach example using such a function type:
>
> public<T> forEach(#void(T) block) throws;
>
> Any exception thrown by the passed-in block can flow-out of the forEach method.
>
>
> Comparisons:
> --------------------
> Strawman:
> #void(String) throws IOException
> public<T, throws E> forEach(#void(T) throws E block) throws E;
> interface Block<T, throws E> { public void invoke(T element) throws E; }
> public<T, throws E> forEach(Block<T, throws E> block) throws E;
>
> Lone throws:
> #void(String)
> public<T> forEach(#void(T) block) throws;
> interface Block<T> { public void invoke(T element) throws; }
> public<T> forEach(Block<T> block) throws;
>
>
> Bytecode:
> --------------------
> Since checked exceptions are a compile-level construct, there are no
> byte-code changes for standard method code. However, there is an open
> question as to what the method signature should be in bytecode.
> Options include:
> a) declare it as Throwable
> b) declare it as a new supertype of Throwable
> c) add a marker flag that indicates it can throw the special any
> exception concept
> d) don't add anything to the signature (however, it would then not be
> possible to catch checked exceptions thrown by "lone throws")
>
>
> Comment:
> --------------------
> I believe that this approach provides exception transparency.
>
> I believe that this approach is easy to specify and implement. (No
> disjunction types or interactions with generics that I can see)
>
> I believe that this approach is easy to learn.
>
> This approach results in a lot simpler syntax for function types, as
> there is no longer a need to declare exceptions. This may open up new
> syntax choices.
>
> This approach results in a lot simpler syntax for exception
> transparent methods. There is no "follow this pattern of boilerplate
> code with throws E twice in generics and also in the throws clause" -
> instead, you just add one keyword.
>
> Current checked exceptions are maintained, however users have the
> choice to effectively turn them off. Given many APIs already do this
> today (by wrapping checked exceptions in unchecked) this would
> probably be used beyond just lambdas. (Checked exceptions remain a
> religious issue for some - this change offers teams a choice as to how
> they are handled.)
>
> Reinier's sort/TreeSet example is fine and simpler (ignoring the fact
> that Set can't be changed in a backwards incompatible way):
>
> Set:
> public boolean add(T t) throws;
> Collections:
> public static<T> void sort(List<T> a, #int(T, T) c) throws { ... }
>
> The approach is less powerful. Some type-information is lost, and it
> is not possible to write exception filtering lambdas that remain
> exception-type-safe. My opinion is that these are edge cases.
>
> My opinion is that it is easy to get caught up in additional
> type-information and type-safety, but Java is so verbose already that
> the impact is necessarily negative. By choosing to reduce the level of
> type-information in the system on this occasion, the end-result is a
> whole lot simpler to understand, and more in tune with how many larger
> open source projects use exceptions today (ie. wrapping any checked
> exceptions).
>
>
> Options:
> --------------------
> One option is to make every method that receives a function type as a
> parameter be a "lone throws" method automatically. There is no
> backwards compatibilty issue, as such methods don't exist today. This
> option has the advantage that developers don't need to know anything
> about exception transparency wrt lambdas. This feels like an
> unecessary extra rule to learn however.
>
> Another option is to allow "lone throws" at the class level. This
> would set all methods in the class to be "lone throws", essentially
> providing a quick way to alter checked exception behaviour for those
> teams that choose. I suspect this would be popular.
>
> There may be a role for a catch clause that doesn't specify the
> exception type. This would effectively 'remove' the "lone throws" from
> the set of exceptions thrown by the block, leaving just the exceptions
> declared in standard method signatures. This would provide the ability
> to wrap these in a RuntimeException or similar if desired. This needs
> more study to determine its usefulness.
>
>
> Stephen
>
More information about the lambda-dev
mailing list