Functional interface confusion

Remi Forax forax at univ-mlv.fr
Sun Jul 7 01:40:33 PDT 2013


Stephen,
And to solve your very specific issue,
while there is no syntax for lambda, you can use a method reference instead.

     static TemporalAdjuster firstDayOfMonth() {
       return TemporalAdjuster::foo;
     }

     static <T extends Temporal> T foo(T temporal) {
       ...
     }

cheers,
Rémi

On 07/07/2013 03:44 AM, Brian Goetz wrote:
> You've pretty much figured it out.
>
> There was some question as to whether to allow the single method in a
> SAM to be a generic method or not.  There's no theoretical problem with
> SAMs that have generic methods, and this works perfectly well with
> method refs: you can assign a method ref for a generic method to a
> (compatible) SAM with a generic method.  But for lambdas, there's no
> syntax for it; you'd need extra syntax to name the type parameter.  (No,
> please don't suggest any; they've all been considered.)  Note that there
> are no problems with SAMs being generic classes; we're only talking
> about methods that themselves introduce generic type parameters, like
> your TemporalAdjuster example.
>
> In the end we decided to go the slightly odd middle ground of not
> prohibiting SAMs with generic methods (after all, they can be used
> perfectly well with method refs) but not inventing a syntax for generic
> lambdas.  We're pretty comfortable with this choice; it comes up rarely,
> and in those rare cases, all you have to do is manually desugar the
> lambda to method, and take a method ref of that.  So TemporalAdjuster is
> a valid SAM, but its harder to use than most SAMs.  For API code, you
> probably do want to avoid this kind of functional interface.
>
> On 7/6/2013 5:39 PM, Stephen Colebourne wrote:
>> I tried to create this interface today, and the compiler complained:
>>
>> @FunctionalInterface
>> public interface TemporalAdjuster {
>>       <T extends Temporal> T adjustInto(T temporal);
>> }
>>
>> static TemporalAdjuster firstDayOfMonth() {
>>     return (temporal) -> temporal.with(DAY_OF_MONTH, 1);
>> }
>>
>> java: incompatible types: invalid functional descriptor for lambda expression
>>       method <T>(T)T in interface java.time.temporal.TemporalAdjuster is generic
>>
>> The same error was seen with this:
>> static <T extends Temporal> TemporalAdjuster firstDayOfMonth() {
>>     return (T temporal) -> (T) temporal.with(DAY_OF_MONTH, 1);
>> }
>>
>> I must admit that I wasn't expecting this, as nothing in the
>> documentation of @FunctionalInterface or other recent discussions that
>> I have seen indicated to me that there is a limitation on lambdas and
>> method-based generics. (FYI, method-based generics are correct here.
>> Generifying the interface TemporalAdjuster would not represent the
>> same logical thing in the codebase. The only constraint is on the
>> method.)
>>
>> By contrast, this seems to work fine:
>>
>> @FunctionalInterface
>> public interface TemporalQuery<R> {
>>       R queryFrom(TemporalAccessor temporal);
>> }
>> static final TemporalQuery<ZoneId> ZONE_ID = (temporal) -> {
>>     return temporal.query(ZONE_ID);
>> };
>>
>>
>> Is the compiler wrong? Is the spec of FunctionalInterface incomplete
>> (perhaps deliberately)?
>> (compiler I'm using is old and on the
>> http://hg.openjdk.java.net/threeten/threeten/jdk branch)
>>
>> I think I understand why the first example cannot be a lambda, as
>> there is no way to grab the <T> in the lambda body, but I'd like a
>> proper explanation! It definitely feels like an awkward edge case, and
>> I suspect I'll be forced back to the ungenerified version.
>>
>> thanks
>> Stephen
>>



More information about the lambda-dev mailing list