Skip to main content

1679. gopy list

What we are porting

Objects/listobject.c (~3500 lines). The most-used mutable container. Append-amortised, sort via Timsort, slice assignment, in-place reverse, the full mutable sequence protocol.

Go shape

// List mirrors PyListObject.
type List struct {
VarHeader
items []Object // len = size, cap >= len
}

We back the list with a Go slice. append already amortises, but CPython's list_resize curve is observable (it determines how often __sizeof__ changes), so we mirror it instead of letting Go choose.

list_resize curve

CPython's growth: new_cap = (size + (size >> 3) + 6) & ~3. Same formula in listResize. The user can probe it via sys.getsizeof.

func listResize(l *List, newLen int) {
needed := newLen
if needed <= cap(l.items) && needed*2 >= cap(l.items) {
l.items = l.items[:needed]
return
}
newCap := (needed + (needed >> 3) + 6) &^ 3
next := make([]Object, needed, newCap)
copy(next, l.items)
l.items = next
}

Sort

list.sort() runs Timsort over the items with the user-supplied key function (or identity). Port from Objects/listobject.c:listsort_impl. Stable; in-place; same merge run lengths CPython picks.

File mapping

C sourceGo target
Objects/listobject.c (struct + ctors)objects/list.go
resize + setitem + sliceobjects/list_resize.go
sortobjects/list_sort.go
richcompare + reprobjects/list_misc.go

Checklist

Status legend: [x] shipped, [ ] pending, [~] partial / scaffold, [n] deferred / not in scope this phase.

Files

  • [~] objects/list.go: List struct, New, FromSlice, Append, Pop, length, getitem, iter, contains. v0.2 placeholder shipped.
  • objects/list_resize.go: listResize mirroring the CPython growth curve; slice assignment with size delta.
  • objects/list_sort.go: Timsort port with key callback, reverse flag, stability.
  • objects/list_misc.go: richcompare (lexicographic), repr, index, count, copy, clear, extend, insert, remove, reverse.
  • objects/list_test.go: resize-curve probe, sort-stability panel, slice-assign size-delta panel.

Surface guarantees

  • sys.getsizeof([1]) matches CPython after the same append history. Pinned by compat/sizeof_test.go.
  • list.sort() is stable.
  • list.sort(key=f) calls f exactly once per item.
  • [1, 2] + [3, 4] returns a new list.
  • list * n for negative or zero n returns [].
  • Slice assignment with size delta moves trailing items exactly once.
  • list is unhashable; hash([1]) raises TypeError.
  • Mutation during iteration raises RuntimeError on the next step (via the version-tag check CPython uses).

Cross-references

  • Sequence protocol: 1683.

Out of scope

  • Free-threaded list element-level locking. Lands in v0.14.
  • array.array. Stdlib.