> On Aug 12, 2026, at 6:17 AM, Johan Sjolen <[email protected]> wrote: > > The problem comes up because of the extreme parametricity of this code along > with the megamorphic nature of the lambda. Let's look at it. > > We have: > > public interface Parser<Context, Problem, Value> extends Function1< > State<Context>, > PStep<Context, Problem, Value> > > public interface Function1<T1, R> extends Serializable, Function<T1, R> { > R apply(T1 var1); > }
For context, this is a good example of one of the limitations described in the JEP: "First, flattening and scalarization require that a variable only stores references to instances of a specific value class; e.g., the date field of a LocalDateTime object always stores a LocalDate reference. Flattening and scalarization typically cannot be applied to a variable declared with a supertype of a value class, such as Object.” "The same principles apply to method parameters: A parameter of type LocalDate is reliably scalarizable, while a parameter of type Object or T is not. (If the method call can be inlined, however, a JIT may be able to skip the assignment and heap allocation completely.)” Unfortunately, it’s not always easy to locate all of these polymorphic variables. And also unfortunately, value object performance is not going to be *strictly better* in all use cases: there are tradeoffs, where certain lower-priority areas of the performance profile have to be degraded in order to enable the big performance gains we want to see in higher-priority areas. Which is not to say there’s nothing that can be done in the platform implementation—more engineering work can often minimize the losses while preserving the gains—but I expect there will always be some trade-offs. > We can help C2 out, by making our apply method carry some more type info, by > giving Parser this override: > > @Override > PStep<Context, Problem, Value> apply(State<Context> state); I guess there are two “best practice” lessons here: - If your program has a bunch of lambdas that operate on the same value class types, declare a specialized interface rather than relying on generic interfaces like `Function`, `Predicate`, etc. - When an abstract class or interface has a generic supertype, parameterized with a value class type argument, it’s helpful to redeclare any abstract method signatures that the type argument appears in. (With the caveat that many simple use cases will just inline and these extra efforts won’t have any impact. But these are simple changes that can help to avoid depending on the whims of inlining.)
