Papers
Topics
Authors
Recent
Search
2000 character limit reached

Persistent Iterators with Value Semantics

Published 15 Apr 2026 in cs.PL | (2604.14072v1)

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.

Authors (2)

Summary

  • The paper presents persistent iterators that allow safe, STL-style iteration over immutable containers, eliminating issues like invalidation and aliasing.
  • It employs finger trees and optimized zippers to achieve efficient, structural-sharing updates while maintaining expected performance.
  • The experimental analysis demonstrates competitive performance and highlights benefits for snapshot-based state management and concurrent workflows.

Persistent Iterators with Value Semantics: A Technical Analysis

Motivation and Problem Statement

The paper "Persistent Iterators with Value Semantics" (2604.14072) addresses the longstanding disconnect between iterator-centric programming in imperative languages and persistent data structures associated with functional paradigms. Conventional STL-style iterators in C++ and similar languages are coupled tightly to mutability and reference semantics, resulting in well-documented hazards such as iterator invalidation, data races, aliasing, and inadvertent side effects. In contrast, persistent (immutable) data structures avoid mutation but typically eschew iterator abstractions, relying instead on combinators or recursion, which often yield suboptimal complexity, inadequate abstraction, or unnatural idioms for imperative workloads. Existing persistent libraries either expose only const iterators or force developers into idioms that substantially diverge from mainstream iterative programming.

The paper introduces the persistent iterator abstraction, reconciling STL-style iterator programming with full value semantics and persistent containers. Persistent iterators snapshot their associated container version, operate on local copies via value semantics, and ensure safety against mutation and invalidation. Critically, persistent iterators support updates (assignment, insertion, erasure) via familiar iterator operations, yet all modifications are local, leaving originating versions untouched and enabling structural sharing. This approach eliminates an entire class of iterator-related bugs and unlocks persistent programming in STL-like idioms.

Design and Underlying Data Structures

The implementation centers on LibFpp, a C++ container library supporting persistent vectors, sets, maps, strings, and other abstractions, built atop finger trees. Finger trees provide a unified, persistent sequence abstraction with asymptotic complexity comparable to array-based STL containers (push_back, pop_back in amortized O(1)O(1), random access in O(logN)O(\log N)). Each container specialization (vector, set, multiset, map, string) is realized as a finger tree with customized monoids for semantic invariants (minimum element, unique keys, Unicode length, etc.).

Representing iterator cursors requires persistent state: LibFpp employs optimized zippers, encoding reversed paths from elements to tree roots. Each zipper node maintains references to tree nodes, child indices, a dirty flag for lazy updates, and parent pointers. Navigation, assignment, insertion, and deletion are achieved by propagating lazy modifications up the path, reconstructing only affected nodes, and exploiting structural sharing for efficiency and value semantics. Figure 1

Figure 1: Example finger trees representing sequences; structural sharing is highlighted to illustrate persistence and efficient updates.

Iterator Abstraction and Semantics

LibFpp persistent iterators provide full STL-like operations including increment/decrement, element access, assignment, insertion, and erasure, but with value rather than reference semantics. Each mutation yields a new iterator-local copy; container extraction (it.value()) reconstructs the persistent container, incorporating local mutations and marked dirty nodes.

Persistent iterators eliminate invalidation and aliasing hazards. Multiple iterators over the same base container operate independently, each referring to its local version. Insertions and deletions never affect the original container or sibling iterators, and previous versions remain available. The abstraction is uniform: all container types employ the same zipper/finger tree foundation, removing asymptotic complexity surprises and abstraction leakage. Figure 2

Figure 2: Example finger tree with zipper paths pointing to distinct positions, showcasing local updates and persistent sharing.

Expressiveness and Programming Patterns

Persistent iterators restore the natural idioms of imperative programming: stateful filtering, rolling snapshots (undo/redo), speculative execution, and iterative transformations can all be expressed without exposing underlying structure or sacrificing performance. In classical STL, algorithms such as filter and stateful iteration require container-specific handling and careful management of invalidation. Functional approaches, while avoiding mutation, often entail deep copies or leak implementation details.

LibFpp achieves optimal complexity (e.g., O(N)O(N) for filtering) while maintaining abstraction and sharing. Patterns like snapshot-based state management (text editors with undo/redo) become trivial: storing iterator or container values captures state in O(1)O(1), avoiding deep copies and enabling persistent workflows.

Performance Analysis

LibFpp is evaluated against STL, Immer, Abseil, and Folly, considering algorithmic complexity, constant factors, and memory overhead. Asymptotically, LibFpp matches STL for most operations; random access and arbitrary jumps incur O(logN)O(\log N) due to tree-based persistence, while insertion and erasure via iterators outperform STL vectors (O(1)O(1) vs O(N)O(N)). Memory overhead is modest and scales with data size, consistent with structural sharing and copy-on-write optimizations.

In microbenchmarks, persistent containers exhibit higher constant factors—sequential access, updates, and appends are slower (3–100x) than array-based mutables, reflecting cache locality and pointer indirection. However, concatenation and split operations benefit from persistence, yielding speedups for certain workloads. LibFpp's custom memory allocator and destructive update optimizations (when reference counts permit) mitigate overheads, yielding competitive performance relative to Immer.

The practical implications are nuanced: persistent containers are not designed as drop-in replacements for STL in performance-critical sections but provide strong safety, abstraction, and persistence for use cases requiring immutability and versioned state.

Theoretical and Practical Implications

This work unifies data structure abstraction by demonstrating that finger trees suffice for persistent implementations of all common container types, and zippers enable efficient STL-style iteration with value semantics. Persistent iterators remove iterator invalidation, make algorithms safer, and allow rollback, snapshotting, and speculative execution in a manner orthogonal to container type and representation.

Persistent data structures are increasingly relevant in safety-critical, concurrent, and versioned software. The design enables idiomatic imperative code under full persistence, bridging the gap between mutable and functional worlds. Future developments may involve broader adoption in languages prioritizing safety, concurrency, and value semantics, as well as deeper integration of persistent abstractions in versioned state management, transactional systems, and speculative computation.

Conclusion

Persistent iterators with value semantics establish a formal, uniform abstraction for STL-style programming over persistent containers, eradicating invalidation and aliasing bugs, guaranteeing safety, and restoring abstraction and expressiveness. LibFpp demonstrates that persistent containers and iterators are practical, performant, and ergonomic for safety-oriented workloads, aligning asymptotic complexity with mainstream STL implementations. This work substantiates the theoretical possibility and practical reality of value semantics for iterative programming, pointing toward persistent data structures as a viable foundation for modern software where safety and immutability are paramount.

Paper to Video (Beta)

No one has generated a video about this paper yet.

Whiteboard

No one has generated a whiteboard explanation for this paper yet.

Open Problems

We haven't generated a list of open problems mentioned in this paper yet.

Collections

Sign up for free to add this paper to one or more collections.

Tweets

Sign up for free to view the 2 tweets with 1 like about this paper.

HackerNews