liveBook · Manning

Memoization

As explained in Fabulous Adventures in Data Structures and Algorithms

A memoized function is a function wrapper that returns cached results for inputs previously evaluated by the original function.

Suppose an immutable quadtree keeps producing the same pattern of cells. Rebuilding that pattern—or recomputing its future—does the same work again. Memoization trades memory for time: it stores a function’s arguments and result, then returns the stored result when those arguments recur. The function must be pure, so its result depends only on its inputs; immutable arguments keep a cached answer valid. section 2.1.5 section 4.3.4 section 10.2

Listing 4.3 A general-purpose one-argument memoizer
sealed class Memoizer<A, R> where A : notnull
{
    private Dictionary<A, R> dict;
    private readonly Func<A, R> f;
    public Memoizer(Func<A, R> f)
    {
        this.dict = new Dictionary<A, R>();
        this.f = f;
    }
    public R MemoizedFunc(A a)
    {
        if (!dict.TryGetValue(a, out R? r))
        {
            r = f(a);
            dict.Add(a, r);
        }
        return r;
    }
    public void Clear(Dictionary<A, R>? newDict = null)
    {
        dict = newDict ?? new Dictionary<A, R>();
    }
    public int Count => dict.Count;
}

The C# memoizer wraps a one-argument function. On a dictionary miss, it calls the original function and stores the result; on a hit, it returns that result without recomputing. Count exposes the cache size, and Clear replaces the dictionary. section 4.3.4

One argument is enough for a quadtree factory: a tuple holds its four children. Memoizing that factory makes equivalent quads reuse one object instead of occupying separate space. An emptiness test can then compare a quad with the cached empty quad by reference. At the extreme, an empty level-60 quad represents a square with 2^60 cells on each side using only 61 objects. section 4.3.3 section 4.3.5

Caching the future

HashLife also applies memoization to a pure Step method. Repeated quads can then reuse computed future states rather than repeat a large recursive calculation. This is a different payoff from memoizing the factory: Step spends cache space to save computation, while the factory deduplicates the data structure itself. section 4.4 section 4.4.4

A cache is not automatically a win. In a 5,000-tick test of small Life configurations, the memoized implementation performed roughly like a naïve array implementation while its Step and Make caches accumulated millions of entries. Just 20 entries accounted for 40% of calls, yet half the entries were never hit again. Measure reuse, watch cache size, and provide a way to clear it: retaining rarely reused results can turn a performance aid into a memory problem. section 4.4.4 section 4.3.4

The same test—will identical inputs recur, and is the saved work worth the memory?—applies beyond Life:

  • Memoizing queue reversal could soften repeated expensive operations during undo and redo. section 2.6.3
  • Memoized term factories could make equality checks use reference equality; memoizing anti-unification itself could replace a repeated-results search. section 10.5

How Fabulous Adventures in Data Structures and Algorithms covers it

How deep it goes
Implements a one-argument C# memoizer, applies it to factories and stepping, and measures cache costs.
Examples
Demonstrates a dictionary-backed C# wrapper, memoized quadtree constructors, and measured Life cache hits.
What it assumes
Assumes familiarity with C# functions and dictionaries; defines purity and constructs the memoizer explicitly.
What you can do after
Build it from scratch with a C# dictionary wrapper, then evaluate whether repeated calls justify its cache.
How it connects
Connects pure functions and immutable data structures to quadtrees, HashLife, reference equality, and cache policy.

Also explained in

Compare how 8 books explain memoization →

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.