Trouble inferring type of lambda
Howard Lovatt
howard.lovatt at gmail.com
Thu Aug 26 02:44:20 PDT 2010
Hi Maurizio,
It is the same source as before but to save you looking things up I
have repeated the relevant bits below:
public interface Method1<R, A1, throws E> { public R call( A1 a1 ) throws E; }
public class IntList11 extends AbstractList<Integer> implements
SortableList<Integer> {
...
@Override public <throws E> void forEach( final Method1<Integer,
Integer, E> method ) throws E { ... }
}
I am not wanting to use (your suggestion):
public <R, throws E> void forEach( final Method1<R, Integer, E>
method ) throws E { ... }
because R can now be anything and hence prevents the compiler catching
type errors (see earlier posts for more details). If I add R it does
indeed compile, but as I said I find the 'cure' worse than the
'problem'. However I am not satisfied with 'my' solution either:
il.forEach( #( i ) {
if ( alwaysTrue() ) { throw new Exception(); }
return 0;
} ); //Need to catch the checked exception!
and hence still searching for something better.
Therefore:
il.<Exception>forEach( #( i ) { throw new Exception(); } ); //Need
to catch the checked exception!
is correct for my signature, the only generic parameter is E, and:
il.forEach( #( i ) { throw new Exception(); } ); //Need to catch the
checked exception!
doesn't compile and I also don't seem to be able to qualify the
statement to 'help' the compiler out (as shown previously).
Your responses are much appreciated,
-- Howard.
On 26 August 2010 18:18, Maurizio Cimadamore
<maurizio.cimadamore at oracle.com> wrote:
> On 26/08/10 07:46, Howard Lovatt wrote:
>>
>> 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!
>>
>
> Hi Howard,
> this is similar to another example we discussed - the inferred return type
> is 'void' and, since return type and argument type should match (same
> type-variable in forEach() signature) inference fails here.
>
> However I noticed that there's a glitch - from your error message I have
> inferred that maybe you are compiling against this signature of forEach
> (again, please post full source, or at least all relevant bits):
>
> <R, throws E> void forEach( Method1<R, T, E> method ) throws
> E;
>
> In that case, the compiler should reject a call such as:
>
> il.<Exception>forEach( #( i ) { throw new Exception(); } ); //Need to catch
> the checked exception!
>
> because there are not enough explicit type-parameters in the method call - I
> guess that a nil-ary type-parameter is being detected here, but an explicit
> 'void' should be used for that one. That's what's causing the compiler to
> fail. If you remove the explicit type as in:
>
> il.forEach( #( i ) { throw new Exception(); } ); //Need to catch the checked
> exception!
>
> The program compiles fine.
>
> Maurizio
>>
>> 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