Skip to content

Unexpected .subList() behavior when getting a [0, size()] slice #361

Open
@Spikhalskiy

Description

@Spikhalskiy

Expected behavior

I have an append-only IntArrayList and I want to take slices of it periodically. I would expect that the following code

var list = new IntArrayList();
list.add(1);
list.add(2);
var snapshot = list.subList(0, 2) // you would expect this never be more than 2 items, right?
list.add(3);
assertEquals(2, snapshot.size()); // assert fails, actually 3
assertEquals(3, list.size());

will lead to snapshot having only the first two elements.

Actual behavior

var list = new IntArrayList();
list.add(1);
list.add(2);
var snapshot = list.subList(0, 2)
list.add(3);
assertSame(list, snapshot); // wat

Root cause

This comes from the following implementation of subList:

	@Override
	public IntList subList(int from, int to) {
		if (from == 0 && to == size()) return this; // this is a good optimization for an unmodifiable collection, but it's not right for a modifiable one.
        ...
	}

Versions

At least [8.5.4, 8.5.15]

Workaround

IntArrayList.SubList and related classes are private.

The best workaround I found so far is to use

new it.unimi.dsi.fastutil.ints.AbstractIntList.IntSubList(list, from, to);

instead, as AbstractIntList.IntRandomAccessSubList that is a superclass of IntArrayList.SubList and is thankfully public.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions