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