Lambda and wildcard
Glavo
zjx001202 at gmail.com
Wed Oct 8 04:01:17 UTC 2025
Hi Tagir,
My bad, I didn't look at the original code carefully. :(
I re-read your email and I think this is still the expected behavior.
In fact, the type of create(() -> makeX()) will be inferred to be X<?
extends X<?>>.
You can capture its return value in a variable in jshell and then verify it
through /vars.
jshell> var x = create(() -> A.makeX())
x ==> null
jshell> /vars
| X<? extends X<?>> x = null
Unfortunately, X<? extends X<?>> and X<X<?>> are not compatible, so the
compilation fails.
Glavo
On Wed, Oct 8, 2025 at 3:53 AM Tagir Valeev <amaembo at gmail.com> wrote:
>
>
> On Tue, Oct 7, 2025, 21:05 Tagir Valeev <amaembo at gmail.com> wrote:
>
>> Hello!
>>
>> The 'makeX' method in my example is not generic, so this part of the
>> specification looks unrelated.
>>
>
> A correction: I meant that the method 'get' of the 'Supplier' functional
> interface is not generic.
>
>
>> With best regards,
>> Tagir Valeev
>>
>> On Tue, Oct 7, 2025, 18:41 Glavo <zjx001202 at gmail.com> wrote:
>>
>>> Hi Tagir,
>>>
>>> This is expected behavior. See Chapter 15 of the Java Language
>>> Specification (Java SE 25 Edition) [1]:
>>>
>>> Unlike a lambda expression, a method reference can be congruent with a
>>> generic function type (that is, a function type that has type parameters).
>>> This is because the lambda expression would need to be able to declare
>>> type parameters, and no syntax supports this; while for a method reference,
>>> no such declaration is necessary. For example, the following program is
>>> legal:
>>>
>>> interface ListFactory {
>>> <T> List<T> make();
>>> }
>>>
>>> ListFactory lf = ArrayList::new;
>>> List<String> ls = lf.make();
>>> List<Number> ln = lf.make();
>>>
>>>
>>> Glavo
>>>
>>> [1]:
>>> https://docs.oracle.com/javase/specs/jls/se25/html/jls-15.html#jls-15.27
>>>
>>> On Wed, Oct 8, 2025 at 12:12 AM Tagir Valeev <amaembo at gmail.com> wrote:
>>>
>>>> Hello!
>>>>
>>>> I'm investigating a seemingly weird compilation case. Consider the
>>>> following Java interface:
>>>>
>>>> import java.util.function.Supplier;
>>>>
>>>> interface Main {
>>>> interface X<T> {
>>>> X<T> self();
>>>> }
>>>>
>>>> static X<?> makeX() {return null;}
>>>>
>>>> static <R> X<R> create(Supplier<? extends R> supplier) {return
>>>> null;}
>>>>
>>>> static X<X<?>> methodRef() {
>>>> return create(Main::makeX).self();
>>>> }
>>>>
>>>> static X<X<?>> lambda() {
>>>> return create(() -> makeX()).self();
>>>> }
>>>> }
>>>>
>>>> I expect that either both methods 'methodRef' and 'lambda' should be
>>>> compilable or both should be non-compilable. However, while 'methodRef'
>>>> compiles, 'lambda' is rejected by compiler (using javac build 25+36-3489):
>>>>
>>>> Main.java:17: error: incompatible types: X<X<CAP#1>> cannot be
>>>> converted to X<X<?>>
>>>> return create(() -> makeX()).self();
>>>> ^
>>>> where CAP#1 is a fresh type-variable:
>>>> CAP#1 extends Object from capture of ?
>>>> 1 error
>>>> error: compilation failed
>>>>
>>>> Could you please help me and clarify whether this is an expected
>>>> behavior or not?
>>>>
>>>> With best regards,
>>>> Tagir Valeev
>>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20251008/837d5b73/attachment-0001.htm>
More information about the compiler-dev
mailing list