Trouble inferring type of lambda

Howard Lovatt howard.lovatt at gmail.com
Wed Aug 25 23:46:43 PDT 2010


Hi Maurizio,

Not sure if the compiler should cope but the current one doesn't:

      il.<Exception>forEach( #( i ) { throw new Exception(); } ); //
Need to catch the checked exception!

Gives:

lambdas/Main.java:163: method forEach in class IntList11 cannot be
applied to given types
      il.<Exception>forEach( #( i ) { throw new Exception(); } ); //
Need to catch the 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>)
1 error

And:

      il.forEach( Method1<Integer, Integer, Exception> #( i ) { throw
new Exception(); } ); // Need to catch the checked exception!

Gives:

lambdas/Main.java:163: 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 the checked exception!
                  ^
  required: Method1<Integer,Integer,Exception>
  found:    #void(?)(Exception)
1 error

So are these compiler bugs or is some other form of qualification possible.

Cheers,

 -- Howard.

On 25 August 2010 18:08, Maurizio Cimadamore
<maurizio.cimadamore at oracle.com> wrote:
> 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.
>>>
>>>
>>
>>
>>
>
>



-- 
  -- Howard.


More information about the lambda-dev mailing list