Collections & LINQ · Lesson 19

Stacks and last-in, first-out history

Reverse a sequence of actions with a deliberately limited undo model.

How it works

A Stack models last-in, first-out behavior. Push places an item on the top, Pop removes the most recently pushed item, and Peek observes the top without removing it. This access pattern is useful for nested tasks, depth-first exploration, and a simple history in which the most recent action must be undone before earlier actions.

A stack of action names is not itself a complete undo system. Real undo may need the previous state, an inverse operation, or enough information to reconstruct a value. The collection only supplies the ordering discipline. Thinking about that boundary helps you design a history record that contains useful state instead of assuming that a label such as edited can somehow restore an earlier document.

Walk through the example. The example starts with an empty text value. Before each edit it pushes the previous text onto the history stack. Two edits produce hello world. Popping then restores hello, and popping again restores the original empty value. The program prints empty explicitly to make the zero-length state visible instead of leaving an ambiguous blank output line.

Watch the boundary. Pop and Peek require a nonempty stack unless you use their Try alternatives. Also consider ownership: storing references to a mutable object does not freeze its past contents. A history of the same mutable list reference repeated several times is not a history of independent snapshots. Store immutable values, independent copies, or well-defined inverse operations.

Practice independently. Extend the example with an Undo function that returns false when no prior state exists. Test undo before any edit, after one edit, and after all history has been consumed. Then add a redo stack and decide when a new edit must clear it. Write the expected state transitions on paper before coding so that both stacks represent a consistent history.

A working example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

var history = new Stack<string>();
string text = "";
history.Push(text); text = "hello";
history.Push(text); text = "hello world";
Console.WriteLine(text);
text = history.Pop();
Console.WriteLine(text);
text = history.Pop();
Console.WriteLine(text.Length == 0 ? "empty" : text);

Expected output

hello world
hello
empty
Try this
A stack supplies undo order; history entries still need independent state or inverse actions.