Functional interface confusion
Stephen Colebourne
scolebourne at joda.org
Sun Jul 7 02:25:15 PDT 2013
Its certainly a pain for me in this case. I understand why its
half-allowed (references only), but I think it has certain issues
still.
Firstly, IntelliJ Idea IDE editor indicated that @FunctionalInterface
was invalid for the interface here. But the compiler did not. So there
is an inconsistency. Given the below, it sounds like a bug in
IntelliJ. If not, then the @FunctionalInterface Javadoc needs
updating.
Secondly, I would prefer that this was valid as a way to resolve the problem:
static <T extends Temporal> TemporalAdjuster firstDayOfMonth() {
return (T temporal) -> (T) temporal.with(DAY_OF_MONTH, 1);
}
Not that it is overly useful as a general construct (it doesn't solve
my problem here), just that it would be easier to explain in a
learning environment, and no doubt occasionally useful. I know you
don't want to hear it, but not supporting the solution above feels
like a bug in the spec to me, given that the whole purpose of defining
actual types in the lambda parameter area is to express a
non-inferable type.
(To be clear, I'm happy enough to agree with the absence of special
syntax on the lambda itself for declaring T)
@Remi, using a method reference is appropriate for the example, but
not in general, as end users will be using this. As such, I have no
choice but to leave it without generics, which makes me sad.
Stephen
On 7 July 2013 02:44, Brian Goetz <brian.goetz at oracle.com> 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