an example of adding a retire list and a recycle function #111
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a toy PR for discussion, not code ready to land. I've seen a couple threads (#52 (comment) and #86 (comment)) where you talked about "retiring" slots, and I wanted to flesh that out a bit.
The main downside of the retirement strategy seems to be that, in exchange for the promise that we'll never see any logic errors (which I really really want), we give up on the idea that our app can run forever. And since generations are included in serialization, this is true even if we save the world to disk and restart our app. Even though the leak is really slow, this is a bummer.
But if we include a "recycle" function, I think we can have the best of both worlds. The contract with the caller would be that they have to go through all the keys in their app and delete all the keys that are dangling (or replace them with null keys) before they call recycle, which resets the version of all free and retired slots to 0. If they get that wrong, then they're exposed to the same logic errors as in the wraparound strategy, just much sooner. Since the leak is so slow in practice, most applications might not bother to recycle at all, but the fact that they have the option could provide "peace of mind".
Aside: We could consider an even more aggressive recycle function, which in addition to setting all empty slots to version 0 also resets all occupied slots to version 1. The caller is already iterating over all their keys, so it might not be any extra work to fix up non-dangling keys at the same time. However, that would introduces a new restriction: If you loop over the same non-dangling key more than once, the first iteration might make that key appear to be dangling, and then the second iteration might incorrectly delete/null the key. So you need the additional guarantee that you're only going to touch each key once. I think most cycle-detection algorithms don't make that tight guarantee, and either way this seems like it would be super error-prone. The additional value of doing this over just recycling empty slots seems super low, so I don't think it's worth introducing the complexity, but it's interesting to think about. I guess it also competes with the more general "copy everything into a brand new slotmap" strategy, which fills holes in addition to resetting versions, and which doesn't require any special support from this crate.