Question on exception transparency
Peter Levart
peter.levart at marand.si
Thu Aug 12 05:40:05 PDT 2010
Hello Maurizio (and Brian),
On 08/10/10, Maurizio Cimadamore wrote:
> Hi
> your code contains an example of circular inference (as the unknown type
> of a lambda parameter is used in order to perform method resolution
> inside the lambda body); there are three ways to solve this:
>
> 1) You can type in the target type explicitly (as you've done); this
> lead to the rather verbose:
>
> foreach(..., Block<String, BlockExecutionException> #(x) {execute(x)});
>
>
> 2) You can secify explicit type-parameters for the 'foreach' method:
>
> <String, BlockExecutionException>foreach(..., #(x) {execute(x)});
>
>
> 3) You can specify the type of the lambda parameter:
>
> foreach(..., #(String x) {execute(x)});
Well, neither of your workarounds (even if applied together - example 2 below) currently works, I believe, because of bugs in the prototype.
But I think it is vital to make the following code (example 1) work:
import java.util.*;
public class Closures
{
public interface Block<T, throws E> { void run(T param) throws E; }
public static <T, throws E>
void forEach(Iterable<T> iterable, Block<? super T, E> block) throws E
{
for (T obj : iterable) block.run(obj);
}
public static void main(String[] args)
{
// example 1:
forEach(
Arrays.asList("a", "b", "c"),
#(String s){ System.out.println("element: " + s); }
);
// example 2 - javac throws NPE:
// Closures.<String, void>forEach(
// Arrays.<String>asList("a", "b", "c"),
// Block<String, void> #(String s){ System.out.println("element: " + s); }
// );
}
}
Example 1 represents the majority of use cases when consuming a generic and exception-transparent API...
If making that code work means changing "a lot of things" including the meaning of "this" and "resolution of members" within lambda body, then I think it is worth it.
On the other hand, if the "feature" of making "this" within lambda body refer to target SAM instance and "resolution of members" within lambda body take SAM instance into consideration first would mean that you always had to specify full SAM type before lambda expression when invoking a generic exception-transparent non-overloaded method, then this "feature" does not in fact help us, since there are workarounds for such situations expressible solely with APIs that demand approximately the same amount of boilerplate and don't require lambdas to support this "feature"...
The following example works with current prototype:
// example 3:
forEach(
Arrays.asList("abc", "def"),
new BlockImpl<String, void>(#(self, s) {
if (!s.isEmpty()) {
System.out.println("element: " + s);
self.run(s.substring(1));
}
})
);
// supporting API...
public interface Block2<T1, T2, throws E> { void run(T1 param1, T2 param2) throws E; }
public static class BlockImpl<T, throws E> implements Block<T, E>
{
private final Block2<Block<T, E>, T, E> block;
public BlockImpl(Block2<Block<T, E>, T, E> block) { this.block = block; }
public void run(T param) throws E { block.run(this, param); }
}
// example to compare amount of boilerplate when prefixing with SAM type (but unfortunately does not yet compile):
forEach(
Arrays.asList("abc", "def"),
Block<String, void> #(s) {
if (!s.isEmpty()) {
System.out.println("element: " + s);
this.run(s.substring(1));
}
}
);
You may argue that no such boilerplate would be necessary when invoking a non-generic and/or non-exception-transparent method using non-generic SAM parameter types, but then this project is not playing well with generics. Generics are not deprecated yet, are they?
Regards, Peter
On 08/10/10, Maurizio Cimadamore wrote:
> Hi
> your code contains an example of circular inference (as the unknown type
> of a lambda parameter is used in order to perform method resolution
> inside the lambda body); there are three ways to solve this:
>
> 1) You can type in the target type explicitly (as you've done); this
> lead to the rather verbose:
>
> foreach(..., Block<String, BlockExecutionException> #(x) {execute(x)});
>
>
> 2) You can secify explicit type-parameters for the 'foreach' method:
>
> <String, BlockExecutionException>foreach(..., #(x) {execute(x)});
>
>
> 3) You can specify the type of the lambda parameter:
>
> foreach(..., #(String x) {execute(x)});
>
>
> The alternative (3) looks the less verbose.
>
> [Note: in this particular case I think there's room for type-inference
> to swallow the circularity, as there's just one 'execute()' method -
> however, in the general case, it is not safe to do so, as there could be
> multiple overloaded version of the called method, or, the thrown types
> of the called method could be generic in a 'throws' type-variable - in
> such cases the 'real' type of the lambda parameter can significantly
> alter the way in which lambda thrown types are inferred - as such, the
> compiler must play the conservative card and infer Exception].
>
> Maurizio
>
> On 10/08/10 07:16, Rizal Anwar wrote:
> > Hi,
> >
> > I played around with the prototype, and I have a question on exception
> > transparency, especially in type inference.
> >
> > I have the following interface:
> >
> >
> > public interface Block<T, throws E> {
> > void run(T param) throws E;
> > }
> >
> > and the following code (assuming ListUtil.foreach is a method accepting a list
> > and a Block).
> >
> > public static void main(String args[]) {
> > List<String> myList = Arrays.<String>asList("A", "B", "K");
> > try {
> > ListUtil.foreach(
> > myList,
> > Block<String, BlockExecutionException> #(x) {execute(x)});
> > ////////////////////////////////////////////////////////////
> >
> > }
> > catch (BlockExecutionException e) {
> > e.printStackTrace();
> > }
> > }
> >
> > private static void execute(String x) throws BlockExecutionException {
> > System.out.println("Execute" + x);
> > }
> > }
> >
> > I wonder whether there is a way not to specify the target Block<String,
> > BlockExecutionException> in the closure I use in the above code ?
> > Isn't is possible to infer the type ?
> >
> > Best regards,
> > Anwar Rizal.
> >
> >
> >
> >
> >
>
>
>
More information about the lambda-dev
mailing list