build-a-spreadsheet-engine / lesson-29.md
Lesson 29 · Incremental recalculation, cycles, and errors

Transitive dependents

Recalculating everything on each edit is wasteful. The first step to doing less is knowing exactly which cells a change can affect - its transitive dependents. Today you compute that set by walking the graph forward.

The goal

Find every cell that transitively depends on a given cell, directly or indirectly.

Start here - the target
TO DO
Scenario: A cell reports everything downstream of it
Givena sheet with A1 set to 1, B1 set to '=A1+1', C1 set to '=B1+1', and D1 set to the literal 100
Whenthe transitive dependents of A1 are computed
Thenthey are B1 and C1, in reading order
AndD1, which reads nothing from that chain, is not among them
Background

When a cell changes, the only cells whose values can possibly change are the ones that read it - directly or through a chain. Those are its transitive dependents, and you find them by following the graph’s dependent edges forward from the changed cell, collecting everything you reach. From A1 the walk reaches B1 (which reads A1) and then C1 (which reads B1); it never reaches D1, because nothing in the chain feeds it.

This forward reachability is the mirror of precedents, which looked backward at what a formula reads. Precedents answer “what do I need before I can compute?”; transitive dependents answer “who do I invalidate when I change?”. That second question is the key to incremental recalculation: instead of recomputing the whole sheet, recompute only this set. The next lesson does exactly that - and orders the set topologically so the downstream cells still evaluate in the right sequence.

Make it work
// follow dependent edges forward from `start`, collecting all reached.
func (s *Sheet) dependentsOf(start Ref) []Ref {
seen := map[Ref]bool{}
var visit func(Ref)
g := s.buildGraph()
visit = func(r Ref) {
for _, d := range g.dependents[r] {
if !seen[d] { seen[d] = true; visit(d) }
}
}
visit(start)
return sortedReadingOrder(seen)
}
CheckpointDONE
A cell can report every cell downstream of it. Commit and stop here.