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