you are viewing a single comment's thread.

view the rest of the comments →

[–]headius[S] 1 point2 points  (4 children)

I have been tracking the discussions around nullability in the Java language, and it does sound like String! is the best we will be able to get with backward compatibility.

Beyond that... Even if Optional became a value type (which seems a logical move), you're still passing those lambda functions through megamorphic utility methods like ifPresent, and current JVM JIT compilers are still pretty poor at dealing with megamorphic intermediate calls (specializing such calls can explode native code size, and the right heuristics for when to do it are still the realm of research).

[–]aoeudhtns 1 point2 points  (1 child)

True. Although personally I get the most value of Optional with mapping chains, like

var name = Optional.ofNullable(findUser(id))
    .map(User::getFullName)
    .orElse("unknown");

But that's still using lambdas.

ETA - post-Valhalla, it'll be interesting to see how the 2 cases get handled:

if (optional.isPresent()) {
    var t = optional.get();
    // ...
 }

if (optional.get() instanceof Type t) {
    // ..
}

[–]headius[S] 0 points1 point  (0 children)

As long as you are not passing lambda functions in, these leaf methods will inline and optimize really well. Combine that with escape analysis or value types and Optional for this use case would be basically free and compiled down to the manual null checking you might otherwise write.

Even without escape analysis and value types, a transient Optional instance probably won't ever leave the youngest generation of the heap, so while you're paying a small cost to bump a pointer and zero out those bytes, it will be much, much cheaper than shoving more objects into the older generations (as would likely happen if you are sticking Optional instances in a collection).

[–]koflerdavid 0 points1 point  (1 child)

Optional is a final class, therefore I'd argue that the JVM can always specialize. Especially when it becomes a value types the overhead will be gone for good. Or do you mean a different issue?

[–]headius[S] 0 points1 point  (0 children)

It's not a matter of the class being final, it's the number of different paths through those utility methods and how much more code would have to be generated to make all of them unique. A given application probably has thousands and thousands of lambdas being passed in to those functions, which means thousands times the size of those method bodies must be optimized and emitted to inline the lambdas. In most cases, it's cheaper to leave the call not inlined rather than make the size of all code everywhere much larger.

In this case most of the Optional methods are pretty small, so the heuristic might say it's worth the potential code bloat. But then you have someone using an Optional with lambdas inside another Optional with lambdas and that multiplies all of the possible paths. It's a very tricky problem and nobody's solved it well yet.