Trouble inferring type of lambda

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Aug 25 01:08:21 PDT 2010


On 25/08/10 06:00, Howard Lovatt wrote:
> 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?
>    
The only option would be to provide explicit type-parameters in the 
method call, as in:

list.<Integer,Exception>forEach(...);

Maurizio



> 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.
>>
>>      
>
>
>    



More information about the lambda-dev mailing list