Skip to main content

Undo and redo require a state model

This lesson uses the behavioral-contracts.zip runtime comparison API. Its policies differ deliberately from core behavioral-patterns.zip; see the contract comparison.

What this concept is​

A local undo history records committed states or reversible operations. Define the state and observation boundary before choosing Command classes, closures or plain functions. The lab uses immutable text snapshots and a cursor into history.

Why it matters here​

Undo correctness depends on failure, no-op and branch behavior, not on whether an object has a method named undo.

Concrete example​

Start with empty text, insert A, insert B, undo, then insert C. States are empty, A, AB; undo returns A; the new edit creates AC and discards the former redo branch. Redo now returns false. By contrast, inserting an empty string after undo is a valid no-op: it creates no entry and preserves the redo branch.

Common confusion / misconception​

Validation after history mutation can corrupt undo even if the visible text stays unchanged. Restoring a text snapshot cannot unsend an email or reverse an external side effect. Local undo is not a distributed transaction rollback.

How to use it​

For insert/delete, validate integer positions (excluding bool), range and string inputs before modifying history. A rejected command preserves text, cursor and redo availability. Deleting zero characters is a no-op. undo/redo return false at the ends without changing state. snapshot returns an immutable tuple (text,cursor,tuple(history)); callers cannot mutate internal history through it. Full snapshots simplify reasoning but retain total text proportional to all history versions.

Check yourself​

After insert A, insert B, undo, and an invalid deletion, should redo still restore AB? What about a valid zero-length deletion?

Mini drill or application​

Write the state transitions and expected snapshots before coding. Compare full snapshots with inverse edits: inverse edits may save storage but require a proof that every inverse restores the intended state under the same history/ownership assumptions.

Read this only if stuck​

Use the existing book/reference map and runtime reading guide. The Design Patterns book index supplies pattern vocabulary; the local lab contract specifies its actual semantics.