liveBook · Manning

Mutable-over-immutable wrapper

As explained in Fabulous Adventures in Data Structures and Algorithms

A mutable wrapper is a mutable object that forwards operations to and replaces its reference to an underlying immutable data structure.

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

How Fabulous Adventures in Data Structures and Algorithms covers it

How deep it goes
Defines forwarding, state replacement, snapshots, undo-redo, and persistence costs, but does not derive the underlying immutable queues.
Examples
Uses C# queue wrappers, an UndoRedo helper, and enqueue-dequeue sequences with undo and redo.
What it assumes
Assumes immutable stacks or queues and teaches how forwarding and persistent state provide mutable-style operations.
What you can do after
Build it from scratch by wrapping an immutable queue or stack and optionally adding persistent undo-redo state.
How it connects
Connects immutable data structures, persistent data structures, undo-redo, and the command pattern.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Fabulous Adventures in Data Structures and Algorithms. The section links point to the parts of the book it draws on.