BGGA's checked exception handling is extremely complex. I don't like
it at all.

I'd much rather have a closure proposal where a method that takes a
closure that has tennant's correspondence principle is strictly
enforced by the compiler to keep the closure stack-safe. In other
words, legal operations are:

1. Running the closure,
2. Grabbing info off of the closure object (running its toString or
some such)
3. passing it on to another method that accepts closures.

You can't assign it to another variable, give it to a method that
isn't designed with these restrictions in mind, assign it to a field,
or letting it escape any other way. This is nice for checked
exceptions, as you can just ignore them, it'll all sort itself out,
but it's also nice because with that restriction, you'll never run
into the situation that break / continue / return in the closure
becomes meaningless (those 3 statements become meaningless if the
stack is gone. The for loop you're trying to break out of is long
gone, so, what exactly is break supposed to do? In BGGA you'd get a
TransferException at runtime. Meh).

If the compiler knows FOR SURE that a given closure is always run so
that the stack as it was when you defined it exists, then there's no
need for all the checked exception generics. Any exception you could
legally throw at the point where you defined the closure is legal to
throw in the closure. Example:

Let's say that, purely for arguments sake, "do" as a keyword modifier
of a parameter signals that it can be a closure, and that you can only
make parameters that are SAMs (types that carry exactly 1 abstract
method).

Then you could write Collections.sort as:

public class Collections {
public static <T> void sort(List<T> list, do Comparator<? super T>
comparator) {
    //do your sort thing.
}


The compiler will then strictly enforce that the sort method doesn't
allow the comparator reference to escape (for its function, there's no
need for that. Contrast to e.g. TreeSet's (Comparator) constructor,
where the comparator must be stored in a field in the treeset, which
would count. You could not stick a 'do' in front of that, the compiler
would refuse to compile that constructor).

Then, you would be able to legally do this in your code:

try {
    Collections.sort(someStringList, #(String a, String b) { new File
(a).getCanonicalPath().compareTo(new File(b).getCanonicalPath()) });
} catch ( IOException e ) {
    //deal with exception.
}

Please don't get hung up on the syntax, consider it pseudocode. I'm
trying to convey the idea that you're calling code that declares
'throws IOException' (getCanonicalPath does that) in a method
(Comparator.compare) which doesn't even let you declare 'throws
IOException'. The compiler will accept this because it knows, _FOR
SURE_, that the closure is always run so that the stack is intact; in
other words, if an IOException does occur, either something in the
mechanics of Collections.sort handles it, or, if it falls through, the
catch block here will handle it. There's no violation of the checked
exception type system; you can't have an IOException in a place that
isn't prepared to handle them.

In BGGA, the mechanism by which the compiler ensures the checked
exception type system is valid is entirely different: Collections.sort
would have to be changed (which isn't possible, backwards
compatibility being the holy grail that it is, so we'd need a sort2
method. Yich!) to accept a parameter 'E' which is the exception type
(s) thrown by the code block. Because you can throw multiple things,
BGGA has a special syntax for this:

public static <T, throws E> void sort(List<T> list, {T => int throws
E} closure) throws E { /*sort method */ }

Here the compiler just binds E to the appropriate exception type, and
as a result, due to the 'throws E' on the sort method itself, this
propagates out.

Now, BGGA has added quite a bit of complexity to make this work:

 - you have this special 'throws E' syntax, which does a special
thing: It will match multiple exception types. so, if you type "throws
IOException, SQLException", and you're implementing a method with
'throws E' where the E is also specified in the generics type var name
as 'throws E', then E will be [IOException, SQLException], which is
something new - having 1 generics letter mean 2 different types.

 - you need to have rather a lot of 'throws E' everywhere. In that
sort line, you have 3 mentions: In the generics var name, in the
function type, and in the method body. Theoretically it could be
different, but that's the pattern in 95% of all cases: The closure can
throw something, and the method, which operates on the closure, just
wants these exceptions to fall right out.

This notion I have of enforcing a closure to run inside stack is also
present in BGGA; after the first prototype, BGGA's break/return/
continue transparency was considered unwieldy because those terms are
meaningless if the stack is gone. Therefore, 2 closure types exist,
differentiated by the perl cartoon swear-esque => and ==> (I forgot
which one meant safe and which one meant unsafe), and you can have
long returns/breaks/continues in only one of the two.


So, if you've got this massive batch of complexity, why not run with
it and at least drop the 'throws E' stuff? Technically the 'throws E'
mechanism of BGGA is more powerful, but I can't think of very many use
cases where you'd ever want to do something with it other than just
pass exceptions right through. By doing it my way you can much more
easily adapt existing code: Just because a parameter has a 'do'
keyword does not mean you HAVE TO pass in a closure. You can pass in
any old Comparator, created in whatever way you like. The 'do' keyword
would simply mean: If you _want me to_, I can handle a closure here,
but it's not mandatory. Therefore, updating an api to add a 'do'
keyword preserves backwards compatibility perfectly. You could just
never remove a 'do' keyword without breaking existing code.


I will be submitting a proposal along these lines (checked exceptions
sorted out this way, a focus on SAMs and not function types, separate
syntax for code blocks and for when you just want to write an
anonymous inner class literal, but with less boilerplate) - if the
closure discussion ever flares up again. Right now closures seem to be
going nowhere, so I'd rather focus on other things. Like project
lombok.

On Aug 18, 8:22 pm, Jess Holle <[email protected]> wrote:
> Reinier Zwitserloot wrote:
> > Concrete examples:
>
> > Runnable does not let you throw Exceptions. Anyone up for defending
> > this grievous API design? The amount of annoyance that this is caused
> > me is almost limitless.
>
> Well Runnable is really for cases where run() should eat any exceptions
> other than things like VirtualMachineErrors -- and should not be used
> for anything else.
>
> That said, this is exactly where BGGA's exception transparency should
> come into play -- to allow you to define:
>
>     public interface Callable<T,E>
>     {
>       public T  call() throws E;
>     }
>
> I will almost certainly get BGGA's proposed syntax muddled here, but the
> important thing here is that call() could throw a precise set of checked
> exceptions and this set would be bubbled up in generic algorithms
> (rather than Exception as in Callable<T> today), e.g.
>
>     public <T,E> visit( Callable<T,E> visitor ) throws SQLException, E;
>
> or some such.  The actual list of checked exceptions emanating from
> visit would be SQLException, IOException, MalformedURLException if E was
> IOException, MalformedURLException.
>
> One can still wrap the exception at any point along the way, of course,
> but one is not /forced /to arbitrarily do so at various points as one is
> today just because of the imprecision of a generic algorithm's declaration.
>
> --
> Jess Holle
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "The 
Java Posse" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/javaposse?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to