Functional interface confusion
Remi Forax
forax at univ-mlv.fr
Sun Jul 7 04:25:31 PDT 2013
On 07/07/2013 11:25 AM, Stephen Colebourne wrote:
> 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);
> }
Casting is never the right incantation when you have trouble with
generics :)
The syntax should be something like this:
(<T extends Temporal> T temporal) -> temporal.with(DAY_OF_MONTH, 1);
otherwise the compiler doesn't know if T is declaration of a type
parameter or
a type variable declared before.
So this syntax is not natural and chance to discover it by yourself is
close to 0.
>
> 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.
but your proposed syntax relies on the fact that the compiler is able to
infer
if T is a declaration or just a use ?
>
> (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.
Writing a generics method (not a lambda, just a generic method) is not
something
users are used to. Framework developers are used to that, not end users.
In your case, if someone want to write a non ISO calendar, asking him/her
to use method references doesn't seem to be a big deal for me.
>
> Stephen
Rémi
>
>
>
> 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