🤖 AI Summary
Traditional mutable containers often suffer from iterator invalidation, aliasing, and data races, while functional persistent data structures struggle to express iterative algorithms naturally. This work proposes a novel persistent iterator abstraction that introduces persistence semantics into the iterator model for the first time: iterators capture a snapshot of the container at creation, support variable rebinding, and retain access to historical versions, thereby reconciling imperative programming idioms with the safety guarantees of value semantics. The accompanying C++ library, LibFPP, implements persistent vectors, maps, sets, and strings using a combination of local copying and structural sharing. It achieves time complexity comparable to the STL while entirely eliminating iterator invalidation, making it well-suited for applications demanding high safety and strong persistence guarantees.
📝 Abstract
Iterators are a fundamental programming abstraction for traversing and modifying elements in containers in mainstream imperative languages such as C++. Iterators provide a uniform access mechanism that hides low-level implementation details of the underlying data structure. However, iterators over mutable containers suffer from well-known hazards including invalidation, aliasing, data races, and subtle side effects. Immutable data structures, as used in functional programming languages, avoid the pitfalls of mutation but rely on a very different programming model based on recursion and higher-order combinators rather than iteration. However, these combinators are not always well-suited to expressing certain algorithms, and recursion can expose implementation details of the underlying data structure.
In this paper, we propose persistent iterators -- a new abstraction that reconciles the familiar iterator-based programming style of imperative languages with the semantics of persistent data structures. A persistent iterator snapshots the version of its underlying container at creation, ensuring safety against invalidation and aliasing. Iterator operations operate on the iterator-local copy of the container, giving true value semantics: variables can be rebound to new persistent values while previous versions remain accessible. We implement our approach in the form of LibFPP -- a C++ container library providing persistent vectors, maps, sets, strings, and other abstractions as persistent counterparts to the Standard Template Library (STL). Our evaluation shows that LibFPP retains the expressiveness of iterator-based programming, eliminates iterator-invalidation, and achieves asymptotic complexities comparable to STL implementations. Our design targets use cases where persistence and safety are desired, while allowing developers to retain familiar iterator-based programming patterns.