lazy statics design notes
brian.goetz at oracle.com
Sat Mar 2 21:46:01 UTC 2019
> The first time someone gets an error because the value of the lazy-static is null,
> they will say "those idiots", etc. Whereas we want them to think of adding laziness
> as a simple, foolproof way to get certain kinds of performance improvements.
And, more people are likely to run into this one, and they are likely to encounter this one far earlier, than some of the other sharp edges.
> So, I don't buy that non-reservation of null is going to especially improve
> the user experience.
You keep saying null, when you mean ‘default value’. For refs, nulls is often an erroneous value for the sorts of things we are likely to stuff into lazy fields, so it seems not-completely-silly. But for ints, zero is a very sensible value, and for booleans, well, it’s half the range.
I don’t really buy the Optional argument either, because the whole reason for having Optional is because nullity is not sufficiently reflected in the type system. (If we had T? types, where blindly dereferencing a T? without a null-safe operation were a compilation error, we wouldn’t need Optional.) Optional allows people to safely express a _restriction type_ on their variables, to get better safety.
Ultimately, these arguments are a reflection of implementation tactics in the language semantics. Not only is this likely to leave users scratching their heads, but as our menu of implementation tactics evolves (welcome, condy!), we might not even need the semantic restrictions that previous tactics required.
This problem is much the same as the problem of compressing the representation so we can express nullable values without increasing the footprint. Obviously in the general case (int, Point) this is problematic, but for a range of common types (pointers, floats, etc), there are bits that can be transparently repurposed, and for others (shorts, bytes, maybe even ints), required padding often produces extra bits. Let’s leave it to the runtime to find these bits; in the worst case, we box primitives, which gives us full range plus we can use null to mean “not initialized”. But that’s an implementation tactic, which is invisible to the user.
More information about the valhalla-spec-observers