[External] : Re: Q: List.of(E... elements) specification with regards to underlying array updates
Stuart Marks
stuart.marks at oracle.com
Tue Sep 2 17:54:14 UTC 2025
On 9/2/25 5:00 AM, Eirik Bjørsnøs wrote:
> On Tue, Sep 2, 2025 at 1:46 PM Eirik Bjørsnøs <eirbjo at gmail.com> wrote:
>
>> Interestingly, List.copyOf [4] explicitly specifies that modifications
>> to the given Collection are not reflected in the returned List. (Even
>> when this may be inferred from the method name!). This prose is what I
>> feel may be missing from List.of(E... elements).
>
> TLDR:
>
> I think my long-winded question boils down to:
>
> Should we add something like the following to List.of(E... elements):
>
> * If the given array is subsequently modified, the returned List will not
> * reflect such modifications.
>
> This would clarify this aspect and provide parity with List.copyOf.
If somebody is genuinely confused by the situation, we could add some
clarifications. I'll observe though that the Java API specifications rely on the
reader to have a lot of implicit knowledge. In a sense, this is a weakness of the
specifications. But if we didn't rely on implicit knowledge, the specifications
would be unbearably cumbersome and verbose.
The implicit knowledge I'm referring to is that, in general, the internal state of
objects in the API is rarely aliased with the state of other objects. This is so
pervasive that it's hardly stated anywhere. Arrays.asList is a notable exception,
which is why people find it confusing, and it's why Venkat and others (including
me!) talk about this issue in presentations. The various collections views (e.g.,
subList, Map.entrySet, etc.) are also exceptions, and the specs go to some effort to
make this clear -- because they're exceptional cases.
The reason that List.copyOf's spec is explicit about modifications is that it needs
to specify that it "makes a copy" while sometimes being allowed not to make a copy!
That is, we wanted to allow List.copyOf to return its argument if the argument is
unmodifiable. However, we didn't want to specify the exact circumstances under which
this occurs. For the same reason, we didn't want to specify that List.copyOf always
makes a copy, as it would preclude this optimization. The "modifications are not
reflected" clause is a bit of specification language that allows us to split the
difference. We avoid making any statements about the identity of the returned
object, but we preserve essential behavior that a mutable collection is copied.
This mostly doesn't apply to List.of(...) though it can if you look really hard.
Most people's experience of List.of is something like
var list = List.of(a, b, c, ..., x, y, z);
It's hard to interpret a clause that says "if the given array is subsequently
modified..." because no arrays are visible here. To understand it, you need to know
that (1) the "given" array is the implicitly generated array that results from a
varargs call, and (2) the implementation of lists created by List.of larger than a
certain size use an array to store their elements. Given this knowledge that there
are two arrays, such a clause would be sensible in that it would require the arrays
not to be aliased. However, without providing all this context, I'm skeptical that
adding such a clause would provide much value.
s'marks
More information about the core-libs-dev
mailing list