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