A DESCRIPTION OF THE PROBLEM :
Currently, lambdas such as `"<string>"::formatted` or `Foo.class::cast` lead to the returned lambda factory being a constructor,
whereas lambda expressions like `(...) -> "<string>".formatted(...)` or `o -> Foo.class.cast(o)` return the same hidden class instance every time.
I propose to extend `LambdaMetafactory.altMetafactory(...)` with a new flag `CONSTANTS` signifying captured constants.
This flag will add `int capturedConstantsCount` and `Object... capturedConstants` to the end of the `altMetafactory` argument list and require that `factoryType` capture no arguments.
Captured constants are prepended to the invocation aguments of the implementation method in place of captured arguments.
`FLAG_CONSTANTS` would then be used when compiling method reference lambdas where the LHS is a constant.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached Java program.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
true
true
true
true
ACTUAL -
false
true
false
true
---------- BEGIN SOURCE ----------
import java.util.function.Function;
public final class LambdaConstantCaptures {
public static final void main(final String... args) {
System.out.println(fn1_Ref() == fn1_Ref() ); // prints `false`, would expect `true`
System.out.println(fn1_Inline() == fn1_Inline() ); // prints `true`
System.out.println(fn2_Ref() == fn2_Ref() ); // prints `false`, would expect `true`
System.out.println(fn2_Inline() == fn2_Inline() ); // prints `true`
}
private static final Function<String, String> fn1_Ref() {
return "Hello %s!"::formatted;
}
private static final Function<String, String> fn1_Inline() {
return arg -> "Hello %s!".formatted(arg);
}
private static final Function<Object, Foo> fn2_Ref() {
return Foo.class::cast;
}
private static final Function<Object, Foo> fn2_Inline() {
return obj -> Foo.class.cast(obj);
}
}
public final class Foo {
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Storing the lambda with captured constants in a `static final` field.
FREQUENCY : always
Currently, lambdas such as `"<string>"::formatted` or `Foo.class::cast` lead to the returned lambda factory being a constructor,
whereas lambda expressions like `(...) -> "<string>".formatted(...)` or `o -> Foo.class.cast(o)` return the same hidden class instance every time.
I propose to extend `LambdaMetafactory.altMetafactory(...)` with a new flag `CONSTANTS` signifying captured constants.
This flag will add `int capturedConstantsCount` and `Object... capturedConstants` to the end of the `altMetafactory` argument list and require that `factoryType` capture no arguments.
Captured constants are prepended to the invocation aguments of the implementation method in place of captured arguments.
`FLAG_CONSTANTS` would then be used when compiling method reference lambdas where the LHS is a constant.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached Java program.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
true
true
true
true
ACTUAL -
false
true
false
true
---------- BEGIN SOURCE ----------
import java.util.function.Function;
public final class LambdaConstantCaptures {
public static final void main(final String... args) {
System.out.println(fn1_Ref() == fn1_Ref() ); // prints `false`, would expect `true`
System.out.println(fn1_Inline() == fn1_Inline() ); // prints `true`
System.out.println(fn2_Ref() == fn2_Ref() ); // prints `false`, would expect `true`
System.out.println(fn2_Inline() == fn2_Inline() ); // prints `true`
}
private static final Function<String, String> fn1_Ref() {
return "Hello %s!"::formatted;
}
private static final Function<String, String> fn1_Inline() {
return arg -> "Hello %s!".formatted(arg);
}
private static final Function<Object, Foo> fn2_Ref() {
return Foo.class::cast;
}
private static final Function<Object, Foo> fn2_Inline() {
return obj -> Foo.class.cast(obj);
}
}
public final class Foo {
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Storing the lambda with captured constants in a `static final` field.
FREQUENCY : always