A mutable-over-immutable wrapper keeps one mutable reference to an immutable data structure. Its public operations forward to that value, then replace the reference with the returned value. The result combines mutable-builder convenience with immutable snapshots. section 2.5
Listing 2.9 A mutable-via-immutable queue
class Queue<T> : IEnumerable<T>
{
private IImQueue<T> q = ImQueue<T>.Empty;
public void Enqueue(T item)
{
q = q.Enqueue(item);
}
public T Peek() => q.Peek();
public T Dequeue()
{
T item = Peek();
q = q.Dequeue();
return item;
}
public bool IsEmpty => q.IsEmpty;
public IEnumerator<T> GetEnumerator() => q.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
A generic C# queue wrapper illustrates the core invariant: Enqueue and Dequeue assign each operation's returned immutable queue back to the private field. section 2.5
The pattern provides:
- A constructor can accept an initial immutable value, while Freeze can return the current immutable snapshot. section 2.5
- A familiar mutable interface without mutating the underlying stack or queue. section 2.5
- Undo and redo by storing successive immutable states instead of defining inverse commands for every mutation. section 2.6.2 section 2.6.3
Undoable queue
An UndoRedoQueue<T> stores an immutable queue inside a reusable UndoRedo<T> helper. Enqueue and Dequeue call Do with the next queue state; Undo and Redo move states between persistent stacks. A sequence of enqueue, undo, redo, dequeue, and undo restores the expected queue contents. section 2.6.3
The extra undo and redo stacks add O(1) work per operation and O(n) stack-node memory for n stored operations. Persistence limits the retained queue-state cost: successive immutable queues share most of their structure, adding O(1) memory on average per state. section 2.6.3
