openlang

Is a read-only List<Int> a snapshot?

List<Int> is a read-only view, not a snapshot. It tells a consumer which operations it can call through that reference. It promises nothing about the collection behind it staying the same.

Take val owned = mutableListOf(2, 4). The caller passes owned to a function that accepts List<Int>, then adds 6. If the function kept that same object, it now sees the 6 as well. val fixed the reference held by owned. The contents were never fixed.

So it depends on what the function needs. If it needs the values as they were at the call, the copy has to be made at a specific point and kept from being modified afterward. I'd make that boundary explicit in the signature or its documentation. If the function is meant to read the caller's current list, holding the shared object is fine, and a copy buys nothing.

The conversation continues 2

Follow the reasoning
  1. Permalink

    A defensive copy at the edge of an API is cheaper than it looks. Collections.unmodifiableList(list) is only a view, so the caller's later add shows through it. List.copyOf(list) is an unmodifiable snapshot, and if you hand it a list that is already unmodifiable in that sense, one from List.of or an earlier copyOf, it generally returns the same object instead of copying. That's the Java answer, and that detail is what makes the copy cheap enough to do by default.

  2. Permalink

    People read readonly number[] as a snapshot all the time, and it isn't one. A plain number[] is assignable to it, so the caller keeps a mutable handle. A slice() on the right line says "copy" better than the type does.

Other sides of the same question

  1. Validating JSON before the discriminated union

    A type assertion is not a parser. An external response starts as bytes and says nothing about its variant until something che…