ReusableBuilder explains that “In general no method other than clear() may be called after result(). It is up to subclasses to implement and to document other allowed sequences of operations (e.g. calling other methods after result() in order to obtain different snapshots of a collection under construction).”
But ListBuffer itself, despite going to considerable trouble to work after result(), doesn’t update the documentation to explain that it’s fine. I think it’s fine.
However, you wouldn’t see the documentation off the type of List.newBuilder, because it’s typed as a mutable.Builder, not a ListBuffer (which it actually is under the hood, as you can see from how it prints out).
It’s worth updating the documentation, and also looking at other subclasses of ReusableBuilder to figure out whether the only-clear-after-result restriction is true in that case.
For instance, ArrayBuilder can usually be extended safely, but not if you happen to call result() when the buffer is full:
scala> val ab = Array.newBuilder[String]
val ab: scala.collection.mutable.ArrayBuilder[String] = ArrayBuilder.ofRef
scala> for c <- "abcdefghijklmnop" do ab += c.toString
scala> ab.result()
val res37: Array[String] = Array(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
scala> ab += "cod"
val res38: scala.collection.mutable.ArrayBuilder[String] = ArrayBuilder.ofRef
scala> ab.result()
val res39: Array[String] = Array(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, cod)
So the documentation is correct: undefined behavior unless you call clear().
Anyway, this could stand a new look, but it is the kind of change that we can make without having to change the binary compatibility of the library. It’s all documentation, bincompat bug fixes, and slightly changed behavior.
If we did want to modify something, perhaps we’d add a snapshot() method (or somesuch) that was guaranteed to return existing work and allow continuation.