Skip to content

Better ImmutableList #3816

Open
wadoon wants to merge 7 commits into
mainfrom
weigl/ilist
Open

Better ImmutableList #3816
wadoon wants to merge 7 commits into
mainfrom
weigl/ilist

Conversation

@wadoon

@wadoon wadoon commented May 16, 2026

Copy link
Copy Markdown
Member

Issue

We currently have two implementations of immutable sequences with ImmutableList and ImmutableArray. This requires conversions sometimes, but mainly it leads to confusion about which implementation should be taken.

Intended Change

This PR unifies everything under ImmutableList.

There are two fresh children classes: ImmutableListArray and ImmutableListList. Both behave like ImmutableList, but use different data storage (T[] or List<T>) in the background.

Some operations from ImmutableList are quite expensive on this data storages, e.g., tail() or reverse(). Therefore, I introduced views that emulate these operations, without copying the data, i.e.,

  • ImmutableListConcat as ImmutableList#prepend(other)
  • ImmutableListReverse for ImmutableList#reverse()
  • ImmutableListSubList for ImmutableList#take(n), ImmutableList#skip(n), ImmutableList#tail()

These operations are now in $O(1)$.

The class ImmutableArray should be considered obsolete.

Developers should use only the methods and functions of ImmutableList. Implementation may override them if there is a faster implementation, e.g, tail() on ImmutableSList.

Plan

  • Renaming ImmutableSList to ImmutableList.
  • More, even more test cases, coverage is not so bad, but could be better.
  • Update the JavaDoc documentation

Type of pull request

  • Refactoring (behaviour should not change or only minimally change)

  • New feature (non-breaking change which adds functionality)

  • There are changes to the (Java) code

Ensuring quality

  • I made sure that introduced/changed code is well documented (javadoc and inline comments).

@wadoon wadoon requested a review from unp1 May 16, 2026 14:55
@wadoon wadoon self-assigned this May 16, 2026
@wadoon wadoon added the Java Pull requests that update Java code label May 16, 2026
@wadoon wadoon added this to the v3.1.0 milestone May 16, 2026
@wadoon wadoon marked this pull request as ready for review May 18, 2026 20:34
@wadoon

wadoon commented May 18, 2026

Copy link
Copy Markdown
Member Author

There is one stupid error in DependencyTracker happening. Currently unclear where it comes from.

wadoon added 6 commits June 13, 2026 16:29
# Conflicts:
#	key.core/src/main/java/de/uka/ilkd/key/proof/init/InitConfig.java
#	key.core/src/main/java/de/uka/ilkd/key/taclettranslation/lemma/TacletLoader.java

@Drodt Drodt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Do you have any idea why tests are failing?

*/
protected void fireProofGoalsAdded(Goal goal) {
fireProofGoalsAdded(ImmutableSLList.<Goal>nil().prepend(goal));
fireProofGoalsAdded(ImmutableList.<Goal>nil().prepend(goal));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably singleton is better here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. On the other side, I wanted to limit my impact. More changes => more errors => more debugging.

Let us wait, until it is green again.

: "p_toMatch and assumes sequent must have same number of elements";
newMC = matchAssumes(
ImmutableSLList.<AssumesFormulaInstantiation>nil().prepend(candidateInst),
ImmutableList.<AssumesFormulaInstantiation>nil().prepend(candidateInst),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

singleton

.createProgramSV(new ProgramElementName("#res_sv"), ProgramSVSort.VARIABLE, false);

final ImmutableList<KeYJavaType> sig = ImmutableSLList.<KeYJavaType>nil()
final ImmutableList<KeYJavaType> sig = ImmutableList.<KeYJavaType>nil()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

singleton

tb.apply(update, tb.prog(modality.kind(), newJavaBlock, target.sub(0)))),
ruleApp.pio);
return ImmutableSLList.<Goal>nil().append(goal);
return ImmutableList.<Goal>nil().append(goal);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return ImmutableList.<Goal>nil().append(goal);
return ImmutableList.<Goal>singleton(goal);

ifInsts.toArray(new PosInOccurrence[0]);
ImmutableList<PosInOccurrence> immutableIfInsts =
ImmutableSLList.<PosInOccurrence>nil().append(ifInstsArr);
ImmutableList.<PosInOccurrence>nil().append(ifInstsArr);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ImmutableList.<PosInOccurrence>nil().append(ifInstsArr);
ImmutableList.<PosInOccurrence>singleton(ifInstsArr);


protected SubIterator(Term t, MutableState mState, LogicServices services) {
termStack = ImmutableSLList.<Term>nil().prepend(t);
termStack = ImmutableList.<Term>nil().prepend(t);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
termStack = ImmutableList.<Term>nil().prepend(t);
termStack = ImmutableList.<Term>singleton(t);

// No functionality is allowed in this method body!
mediator.getUI().getProofControl().startAutoMode(r.getSelectedProof(),
ImmutableSLList.<Goal>nil().prepend(invokedGoal));
ImmutableList.<Goal>nil().prepend(invokedGoal));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ImmutableList.<Goal>nil().prepend(invokedGoal));
ImmutableList.<Goal>singleton(invokedGoal));

PosInOccurrence pos) {
if (pos == null) {
return ImmutableSLList.<Integer>nil().prepend(0);
return ImmutableList.<Integer>nil().prepend(0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return ImmutableList.<Integer>nil().prepend(0);
return ImmutableList.<Integer>singleton(0);

*/
private DefaultImmutableSet(T element) {
elementList = (ImmutableSLList.<T>nil()).prepend(element);
elementList = (ImmutableList.<T>nil()).prepend(element);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
elementList = (ImmutableList.<T>nil()).prepend(element);
elementList = ImmutableList.<T>singleton(element);

*/
ImmutableList<T> append(@SuppressWarnings("unchecked") T... array);
default ImmutableList<T> append(ImmutableList<T> list) {
return new ImmutableListConcat<>(this, ImmutableList.fromList(list));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return new ImmutableListConcat<>(this, ImmutableList.fromList(list));
return new ImmutableListConcat<>(this, list);

Would this not also work?

@Drodt Drodt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Do you have any idea why tests are failing?

public ImmutableList<T> take(int n) {
List<T> seq = new ArrayList<>(Math.min(size(), n));
ImmutableList<T> list = this;
for (int i = 0; i < seq.size(); i++) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seq.size() is 0 here so the loop is never executed


@Override
public ImmutableList<T> removeAll(T obj) {
return stream().filter(it -> Objects.equals(obj, it)).collect(ImmutableList.collector());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!Object.equals

@Override
public int hashCode() {
return Objects.hash(list, start, end);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in ListConcat and ListReverse the hascode is structural, while in Cons and ListList element-wise

equals is always element-wise

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Java Pull requests that update Java code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants