Trouble inferring type of lambda

Howard Lovatt howard.lovatt at gmail.com
Tue Aug 24 22:00:03 PDT 2010


Having tried:

@Override public <R, throws E> void forEach( final Method1<R, Integer,
E> method ) throws E {
   for ( int i = 0; i < values.length; i++ ) {
     final Integer oldValue = values[ i ];
     final R newValueTemp = method.call( oldValue );
     if ( newValueTemp instanceof Integer ) { values[ i ] = (Integer)
newValue; }
     else { throw new IllegalArgumentException(); }
   }
 }

To overcome the problem that:

  list.forEach( #( i ) { throw new Exception() } );

Wouldn't normally work (because the lambda returns void and not
Integer). The problem with the above forEach implementation is that
the return type is unconstrained and hence effectively unchecked by
the compiler and generates runtime exceptions.

Therefore the best I have come up with is:

  list.forEach( #( i ) {
    if ( alwaysTrue() ) { throw new Exception(); }
    return 0;
  } );

Which I am not really satisfied with, is there better?

Cheers,

 -- Howard.


On 23 August 2010 22:49, Howard Lovatt <howard.lovatt at gmail.com> wrote:
> Thanks for the reply.
>
> Whilst this will work, it is hardly desirable. Effectively the return
> type of all lambdas has to 'free' variable then writing a method that
> uses them is awkward, e.g.:
>
>  @Override public <R, throws E> void forEach( final Method1<R,
> Integer, E> method ) throws E {
>    for ( int i = 0; i < values.length; i++ ) {
>      final Integer oldValue = values[ i ];
>      final R newValueTemp = method.call( oldValue );
>      if ( newValueTemp instanceof Integer ) { values[ i ] = (Integer)
> newValue; }
>    }
>  }
>
> Not great!
>
> Cheers,
>
>  -- Howard.
>
> On 23 August 2010 21:59, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> wrote:
>> On 23/08/10 12:34, Howard Lovatt wrote:
>>>
>>> Thanks for the clarification, I think it *should* be a bug!
>>>
>>> In the meantime, what is the recommended idiom for writing such a
>>> function.
>>>
>>
>> You could try with:
>>
>> interface SortableList<T extends Comparable<? super T>> extends List<T> {
>>
>> <R, throws E> void forEach( Method1<R, T, E> method ) throws E;
>>
>> }
>>
>> this should do.
>>
>> Maurizio
>>
>>>  -- Howard.
>>>
>>> On 23 August 2010 21:15, Maurizio Cimadamore
>>> <maurizio.cimadamore at oracle.com>  wrote:
>>>
>>>>
>>>> On 23/08/10 12:02, Howard Lovatt wrote:
>>>>
>>>> Hi Mauritzio,
>>>>
>>>> I think it is a bug, like I said in the original post the 'return
>>>> type' is 'NeverReturns' not void, which should be assignable to
>>>> anything (including Integer). Scala and BGGA handle this case, they
>>>> both have a 'NeverReturns' type (Scala and BGGA Nothing).
>>>>
>>>>
>>>> Let me clarify - it is not a bug, according to the current spec; quoting
>>>> from the latest formal spec describing lambda conversion [1]:
>>>>
>>>> "A divergent lambda expression such as #(){throw new AssertionError();}
>>>> has no return value, and its body completes abruptly by reason of a
>>>> throw with an AssertionError object. For the purpose of calculating
>>>> the type of the lambda expression, the body of the lambda expression
>>>> is void."
>>>>
>>>> [1] -
>>>>
>>>> http://mail.openjdk.java.net/pipermail/lambda-dev/attachments/20100212/af8d2cc5/attachment-0001.txt
>>>>
>>>> Maurizio
>>>>
>>>> Cheers,
>>>>
>>>>  -- Howard.
>>>>
>>>> On 23 August 2010 20:35, Maurizio Cimadamore
>>>> <maurizio.cimadamore at oracle.com>  wrote:
>>>>
>>>>
>>>> This is not a bug. You are trying to SAM convert the following lambda:
>>>>
>>>> #(x) { throws Exception(); }
>>>>
>>>> into the following target method:
>>>>
>>>> <throws E>  Integer call( Integer a1 ) throws E
>>>>
>>>> This is not possible, since the lambda expression is inferred to yield
>>>> 'void' (no return expression found), while the target method returns
>>>> Integer.
>>>>
>>>> Maurizio
>>>>
>>>>
>>>>
>>>> On 22/08/10 18:45, maurizio cimadamore wrote:
>>>>
>>>>
>>>> On 22/08/2010 07:09, Howard Lovatt wrote:
>>>>
>>>>
>>>>
>>>> For:
>>>>
>>>>    public interface Method1<R, A1, throws E>     { public R call( A1 a1 )
>>>> throws E; }
>>>>
>>>> and:
>>>>
>>>>    public<throws E>     void forEach( final Method1<Integer, Integer, E>
>>>> method ) throws E { ... }
>>>>
>>>> The compiler has trouble with:
>>>>
>>>>     il.forEach( #( i ) { throw new Exception(); } ); // Need to catch
>>>> checked exception
>>>>
>>>> Giving:
>>>>
>>>> lambdas/Main.java:34: method forEach in class IntList11 cannot be
>>>> applied to given types
>>>>        il.forEach( #( i ) { throw new Exception(); } ); // Need to
>>>> catch checked exception
>>>>          ^
>>>>    required: Method1<Integer,Integer,E>
>>>>    found: #void(?)(Exception)
>>>>    where E is a type-variable:
>>>>      E extends Exception declared in method
>>>> <E>forEach(Method1<Integer,Integer,E>)
>>>>
>>>> Qualifying doesn't help:
>>>>
>>>>    Method1<Integer, Integer, Exception>     #( i ) { throw new
>>>> Exception();
>>>> }
>>>>
>>>> It gives:
>>>>
>>>> lambdas/Main.java:34: incompatible types; no instance(s) of type
>>>> variable(s) ? exist so that #void(?)(Exception) conforms to
>>>> Method1<Integer,Integer,Exception>
>>>>        il.forEach( Method1<Integer, Integer, Exception>     #( i ) {
>>>> throw
>>>> new Exception(); } ); // Need to catch checked exception
>>>>                    ^
>>>>    required: Method1<Integer,Integer,Exception>
>>>>    found:    #void(?)(Exception)
>>>>
>>>> Is the problem that the return type isn't expressible? It isn't really
>>>> void, it is 'NeverReturns'.
>>>>
>>>>
>>>>
>>>>
>>>> Uhmm the problem here seems more related with a failure in inference of
>>>> the lambda parameter (the '?' that you are seeing). Again it would be
>>>> helpful to see the declaration of the receiver class as well as the type
>>>> of 'il'.
>>>>
>>>> Maurizio
>>>>
>>
>>
>
>
>
> --
>   -- Howard.
>



-- 
  -- Howard.


More information about the lambda-dev mailing list