CSV Keys and the Iteration Problem
Here’s a problem that sounds trivial until you’re staring at it: you need to save a hash table to disk and load it back, but your save format has no way to list the keys in a section.
You can write a key-value pair. You can read a key-value pair if you know the key. But you can’t ask “what keys exist here?”
The Constraint
This comes up with section-based save systems. The API gives you write(key, value) and read(key, default). Clean, simple, type-safe. But it assumes you know ahead of time what you’re looking for.
That works for fixed schemas — player name, health, level. It breaks for dynamic data — unlocked items, per-character stats, achievement progress. The set of keys isn’t known at compile time. It grows as the player plays.
The Pattern
The solution is almost embarrassingly simple: save a manifest alongside the data.
When writing, build a comma-separated list of all keys as you iterate the hash table. Write each value under its own key, then write the key list under a special _keys entry.
When reading, read _keys first, split on commas, then iterate the resulting array to read each value by name.
Why It Works
The pattern is self-describing. The save file contains everything needed to reconstruct the data — no external schema, no version-specific knowledge of what keys might exist. Add a new unlock type six months from now and the save system handles it automatically.
It’s also resilient. If a key appears in _keys but the value is missing, the read function returns the default. If a value exists but isn’t in _keys, it’s safely ignored. Forward and backward compatibility for free.
The Tradeoff
You’re storing redundant data. The keys appear twice — once in the manifest, once as actual entries. For most game save data, this is negligible. If you’re serializing millions of entries, you’d want something smarter.
But for the common case — dozens to hundreds of dynamic entries — the simplicity wins. No custom parser, no schema migration, no iteration API needed. Just strings and commas.
Sometimes the best data format is the one you already have, plus a little metadata.