stack-bound vs. travelling closures proposal.

Brian Goetz brian.goetz at oracle.com
Wed Jun 16 22:21:17 PDT 2010


Overall, there's a lot to like about the "stack-bound vs traveling" 
distinction.  As pointed out earlier, this is the gating concern on nonlocal 
control flow, as well as what enables mutable local capture to not be nearly 
guaranteed to be racy.

Having said that, I am not convinced it is the right vehicle for exception 
transparency, because it violates a basic principle: that method signatures 
declare the checked exceptions they throw.  (Yes, I know about many ways 
exceptions can be thrown sneakily.)

> note the "do" keyword there. It can be any keyword, such as "restricted",
> that's a detail that can be decided on later. What this does is two things:
> First of all, the compiler will ensure that the "c" variable is not assigned
> to anything (be it a field or a local variable), is not captured by a
> non-restricted closure, is not captured by a method local class, is not
> returned, and is not passed as variable to another method (with one
> exception: It's okay to pass c as a closure to another method that also has
> a 'do' keyword for that parameter).

This is similar to the treatment of const in C++.  To make this safe, this 
really has to be part of the type system, where the restricted-ness is 
incorporated into the function type (so function types would subsume return 
type, argument types, exception types, and restricted-ness.)  And the 
restricted-ness for a closure argument has to become part of the method 
signature.  And switching a closure parameter between restricted and not 
becomes a binary-incompatible change.  And it doesn't stop at function types; 
the restricted-ness bit has to stick to any SAM reference type.

Note there's really two aspects here to restricted-ness; the first is that you 
can't intermix restricted and nonrestricted closures; the second is a 
requirement for a form of non-escapingness.

Note that neither "restricted T->U" and "unrestricted T->U" are subclasses of 
each other; if either direction held, either you'd be able to pass a 
restricted closure to a unrestricted parameter (allows escape) or an 
unrestricted closure to a restricted parameter (safety violation.)

> Then, IF a closure is passed directly as parameter, one gets hassle-free
> exception transparency, and one can legally write this:
>
> public void test() throws IOException {
>      Collections.sort(someList, #(String a, String b) {
>          if (a == null) throw new IOException();
>          return a.length() - b.length();
>      });
> }

So, are you basically saying that "for methods taking restricted closure 
parameters, the method is considered to throw any exceptions that might be 
thrown by the restricted closure(s)."  But this isn't embodied in the method 
signature; its as if the method does not have a choice whether to catch or 
expose those exceptions.  You might call this "forced exception transparency", 
since methods like sort() are forced to expose any of the exceptions that 
might be thrown by their closure arguments (even if they intend to catch them.)

> There's only one caveat: The author of the Collections.sort method may
> presume that any call to Comparator.compare() couldn't possibly throw, say,
> an IOException, because "compare()" does not declare this. And that would be
> a mistake - this entire concept is predicated on the notion that any checked
> exception not explicitly declared by that closure falls "through" all
> intermediate methods right back to the original lexical scope, at which
> point it'll be handled. This fall-through scheme can only work if none of
> the intermediate methods catch the exception.

This is a pretty big deal!

> (1) Any java program that works like the above and assumes that IOException
> must have come from the FileInputStream is already buggy. It's the JVM
> you're coding for and not java (the language) programs; class files produced
> by jython, scalac, jruby, and just about any other alternative language
> routinely throw checked exceptions "sneakily". Even within the constraints
> of java itself, sneaky exceptions can happen. If not explicitly (via e.g.
> someClass.newInstance() which can sneaky throw), then implicitly, by mixing
> class files from different compile runs. Thus, this isn't really a new
> caveat.

This is a pretty shaky argument.  Theft happens in the real world; the cure is 
not to declare that property rights are an untenable abstraction.

>   A. Add an 'unshackle' utility method that takes in any parameter (even a
> restricted one) and returns it.

Much like casting away constness in C++.

Overall I like the restrictedness concept for its other valuable properties, 
but I am not so hot on piling on exception transparency.  Bottom line: method 
signatures should declare their checked exceptions.



More information about the lambda-dev mailing list