Fact-checked by Grok 2 weeks ago

Iterator

An iterator is a behavioral design pattern in object-oriented programming that provides a method for accessing the elements of an aggregate object, such as a list or tree, sequentially without revealing the object's underlying representation. This pattern, one of the 23 classic patterns cataloged in the 1994 book Design Patterns: Elements of Reusable Object-Oriented Software by , Richard Helm, Ralph Johnson, and John Vlissides (known as the ), separates the responsibility of traversal from the collection itself, enabling uniform iteration across diverse data structures. The core structure of the Iterator pattern includes an iterator interface defining operations like checking for the next element (hasNext) and retrieving it (next), concrete iterator classes that implement traversal algorithms specific to a collection type, and an aggregate interface that supplies iterators without exposing internal details. This design supports multiple concurrent traversals on the same collection, polymorphic iteration over subclasses of aggregates, and simplified client code by abstracting complex navigation logic. Key benefits encompass reduced between clients and collections, elimination of duplicated traversal code, and enhanced flexibility for varying iteration strategies, such as forward-only or bidirectional traversal. Iterators are fundamental to modern programming languages and libraries. In Java, the java.util.Iterator interface facilitates safe removal of elements during traversal and is central to the Collections Framework, enabling enhanced for-each loops via the Iterable interface. Python implements iterators through objects supporting the iterator protocol with __iter__() and __next__() methods, powering efficient, memory-conserving loops over sequences and custom data types. Similarly, C++ employs iterators as generalized pointers in the Standard Template Library (STL), allowing algorithm-generic traversal of containers like vectors and lists with categories such as input, output, forward, bidirectional, and random access. These implementations underscore the pattern's role in promoting reusable, efficient code for data processing across domains like algorithms, data structures, and software frameworks.

Fundamentals

Definition and Purpose

An iterator is an object that facilitates to the elements of a or structure, such as , , or , without revealing its internal representation. This enables clients to traverse collections uniformly, regardless of the underlying details. Typically, an iterator provides core methods like next() to retrieve the current element and advance to the next one, along with hasNext() to check if more elements remain, allowing controlled until the end of the sequence. The primary purpose of an iterator is to abstract the traversal logic from the collection itself, promoting a separation of concerns where the iteration operates independently of the structure's specifics. This abstraction supports consistent access patterns across diverse collections, such as linear structures like arrays or hierarchical ones like graphs, while enabling operations like detecting the end of iteration without direct indexing. By encapsulating traversal, iterators allow for multiple simultaneous traversals over the same collection and facilitate the development of generic algorithms that work polymorphically with heterogeneous types. Key benefits include enhanced encapsulation, as the internal structure of the collection remains hidden from clients, reducing and improving . Iterators also enable polymorphic behavior, permitting the same iteration code to handle different collection types seamlessly, which supports the open-closed principle by allowing new iterators without modifying existing collection classes. Additionally, this pattern aids in and resource efficiency by advancing only as needed during traversal. A basic iterator interface can be illustrated in pseudocode as follows:
interface Iterator {
    boolean hasNext();
    Object next();
    void remove();  // Optional, for safe removal of current element
}
This interface defines the essential operations for traversal, where hasNext() returns true if additional elements are available, next() fetches and returns the next element while advancing the position, and remove() optionally deletes the last returned element without exposing the collection's internals.

Historical Development

The concept of iteration in programming traces its roots to the late 1950s and early 1960s, when early high-level languages introduced primitives for sequential data access. In , developed in 1958 by John McCarthy and his team at , list traversal was enabled through fundamental operations like car (access first element) and cdr (access rest of list), allowing recursive processing of linked structures without exposing internal representations. Similarly, , released in 1960, formalized structured iteration via the for-loop construct, which provided a controlled way to repeat operations over sequences, influencing subsequent procedural languages by separating loop control from data access. The formalization of iterators as a distinct abstraction emerged in the 1970s amid the rise of modular and object-oriented paradigms. Simula 67, introduced in 1967 but widely adopted through the 1970s, pioneered class-based constructs for simulation, laying groundwork for object-oriented encapsulation of behaviors. This evolved further with CLU, developed at MIT starting in 1974 by Barbara Liskov and her team, which explicitly introduced iterators as first-class language features—procedures that yield successive elements from aggregates, supporting abstract data types and parameterization for reusable traversal independent of underlying storage. CLU's iterators emphasized separation of iteration logic from collection implementation, a principle that became central to later designs. The 1990s marked the iterator's popularization as a standardized in . In 1994, the "Gang of Four" book Design Patterns: Elements of Reusable Object-Oriented Software by , Richard Helm, Ralph Johnson, and John Vlissides formalized the as one of 23 behavioral patterns, defining it as a mechanism to access aggregate elements sequentially without revealing internal structure, drawing from earlier influences like CLU. That same year, and colleagues released the (STL) for C++, incorporating iterators as generic pointers for algorithm-container decoupling, enabling efficient, type-safe traversal across diverse data structures. Java followed in 1998 with the Collections Framework in JDK 1.2, integrating the Iterator interface into its core libraries to unify traversal over collections like lists and sets, replacing ad-hoc enumerations. By the 2000s, iterators evolved from primarily procedural and object-oriented forms toward functional and lazy variants, enhancing expressiveness for large-scale and infinite . Python 2.2, released in December 2001, introduced generators via PEP 255, allowing functions to yield values on-demand for memory-efficient lazy iteration over potentially unbounded sequences. This trend continued with (Language Integrated Query) in .NET 3.5 in , which extended iterators through composable query operators on IEnumerable, blending imperative and declarative styles for functional-style processing in mainstream object-oriented environments. These developments shifted focus from rigid to flexible, deferred computation, accommodating and demands.

Design Pattern

Overview of the Iterator Pattern

The is a behavioral that enables to the elements of an aggregate object, such as a collection, without revealing its internal representation. This approach encapsulates the traversal logic within dedicated iterator objects, allowing clients to iterate over data structures uniformly regardless of their underlying implementation. By abstracting away from the collection itself, the pattern promotes flexibility in handling diverse types while maintaining a consistent for consumers. The pattern is particularly applicable when working with collections that have heterogeneous internal structures, such as arrays, linked lists, or , where direct exposure of the representation would complicate client code. It also proves valuable in scenarios requiring multiple simultaneous traversals over the same collection, as each iterator maintains its own state independently. This makes it suitable for applications involving dynamic data access, where the traversal mechanism needs to remain decoupled from the storage details to support polymorphism and extensibility. Key participants in the Iterator pattern include the Iterator, which defines a common for traversal operations like next() and hasNext(); the ConcreteIterator, which implements this interface for a specific ; the interface, providing a createIterator() method; and the ConcreteAggregate, which returns an appropriate ConcreteIterator instance. These components collaborate to separate concerns, with the aggregate focusing solely on element management and the iterator handling access logic. Among its benefits, the Iterator pattern adheres to the by isolating traversal responsibilities, thereby reducing complexity in both the collection and client code. It simplifies development by iteration from the aggregate's storage mechanism, enabling easier maintenance and support for varied traversal strategies without altering the collection's core. This enhances reusability and , as iterators can be mocked or substituted independently. Known uses of the are prevalent in toolkits for traversing hierarchical menu structures, allowing uniform navigation across composite components without exposing their layout. Similarly, it is employed in database layers, such as JDBC's ResultSet , to sequentially process query results while abstracting the underlying mechanism.

Structure and Components

The Iterator design pattern is structured around two core interfaces: the Aggregate (or Collection) interface and the Iterator interface. The Aggregate interface defines a single method, typically createIterator(), which returns an instance of the Iterator interface, enabling the creation of iterators for traversing the aggregate's elements. The Iterator interface specifies the essential operations for sequential access, including hasNext() (or hasMore()) to determine if additional elements remain and next() (or getNext()) to retrieve and advance to the subsequent element; optional methods such as currentItem() for accessing the current element without advancing the position or remove() for deleting the most recently returned element may also be included. Concrete classes implement these interfaces to provide specific functionality. A ConcreteAggregate, such as an ArrayList or a custom collection like a , realizes the Aggregate by maintaining the underlying data and implementing createIterator() to instantiate an appropriate ConcreteIterator based on the collection's . The ConcreteIterator implements the Iterator , tracking the traversal state—often via an internal index, pointer, or cursor—to manage the current position and ensure sequential access without exposing the aggregate's internal details. The interaction sequence begins with the client invoking createIterator() on the to obtain an iterator instance. The client then enters a loop, repeatedly calling hasNext() to check for remaining elements and next() to fetch them, continuing until hasNext() returns false, at which point the traversal is complete. This process allows the client to decouple from the 's , supporting polymorphic iteration over diverse collection types. Responsibilities in the pattern are distinctly separated to promote encapsulation and flexibility. The Iterator bears the sole duty of managing traversal state, such as the current position, enabling multiple independent iterators to coexist and operate on the same without mutual interference or shared mutable state. Conversely, the focuses exclusively on iterator creation, delegating all navigation logic to the iterator while preserving its role as a for the elements. In a textual representation of the UML class diagram, the Iterator interface is depicted as an abstract class or interface with methods like hasNext() and next(), from which one or more ConcreteIterator classes inherit or implement, each tailored to a specific type (e.g., a forward-only iterator for lists). The interface, featuring the createIterator() method, is similarly abstract, with ConcreteAggregate classes implementing it and holding a dependency or association to the relevant ConcreteIterator, which they instantiate upon request. A client class interacts solely with the two interfaces, invoking createIterator() on the and then utilizing the iterator's methods, thereby illustrating the pattern's use of to hide concrete class details and enforce .

Variations and Extensions

External and Internal Iterators

External iterators and internal iterators represent two fundamental approaches to implementing the Iterator design pattern, differing primarily in the during traversal. In external iterators, the client explicitly manages the iteration process by querying the iterator for the next element and deciding when to stop, providing a pull-based model where the client drives the sequence of operations. This approach aligns with the core structure of the , where the iterator object maintains its own state independently of the client. External iterators offer fine-grained control, allowing clients to pause, resume, or alter the traversal dynamically, such as comparing elements from multiple collections or supporting concurrent traversals from different starting points. For instance, a typical implementation involves a that for availability before advancing:
while (iterator.hasNext()) {
    [element](/page/Element) = iterator.next();
    // Process [element](/page/Element)
}
This flexibility comes at the cost of increased , as the must handle the iteration manually, which can lead to more verbose code and potential errors in . According to Gamma et al., external iterators are particularly advantageous in languages like C++ where closures are absent, enabling reusable traversal logic across aggregates. In contrast, internal iterators adopt a push-based model where the collection or object controls the traversal, applying a client-provided to each in without exposing the iteration mechanics to the client. This is common in paradigms, simplifying client code by encapsulating the loop logic within the iterator. A representative example uses a forEach-style method:
collection.forEach([function](/page/Function)([element](/page/Element)) {
    // Process [element](/page/Element)
});
Internal iterators reduce boilerplate and promote declarative code, making them easier to read and less prone to iteration-related bugs, as noted by in his analysis of iterator essences. However, they limit client control, often prohibiting early termination or custom ordering without additional mechanisms like , and they typically support only one traversal at a time. Gamma et al. highlight that internal iterators excel in environments supporting higher-order functions, such as Smalltalk's block-based do: method, but may require subclassing for specialized operations. The trade-offs between these approaches depend on the application's needs: external iterators suit scenarios requiring complex, interruptible logic or multi-iterator coordination, while internal iterators prioritize simplicity and abstraction in straightforward traversals. Both maintain the pattern's goal of traversal from representation, but external variants enable more intricate control flows at the expense of usability.

Generators and Lazy Evaluation

Generators represent a specialized form of iterator implemented as functions that produce a of values incrementally, yielding each one rather than materializing the entire collection upfront. This approach allows generators to function as iterators by providing a next-value mechanism that advances through the without requiring the full computation at initialization. is integral to generators, wherein computation is deferred until the values are actually requested during , enabling the handling of potentially infinite such as the numbers without immediate resource exhaustion. This strategy contrasts with eager evaluation, which computes all elements immediately upon creation, often leading to unnecessary work for unused portions of the data. In generators, ensures that only the demanded elements are generated, promoting efficiency in scenarios where full traversal may not occur. The primary benefits of generators with include significant memory savings for processing large or unbounded datasets, as storage is proportional only to the consumed portion rather than the entire potential output. Additionally, this design enhances , allowing generators to be integrated into pipelines where downstream operations dictate the extent of upstream computation, thereby supporting modular program construction. Mechanically, a maintains internal —such as local variables and —across successive yields, suspending execution after producing a value and resuming from that point on the next request. The is exhausted once the underlying completes or no further values can be produced, at which point iteration terminates. This persistence distinguishes generators from one-shot functions while aligning them with external iterator patterns that emphasize client-controlled advancement. Common use cases for generators include streaming data processing, where values are generated on-the-fly for real-time analysis, and algorithmic tasks like producing prime numbers sequentially without storing the full list, which is particularly valuable in resource-constrained environments or for exploratory computations.

Streams and Pipelines

Streams provide an abstract representation of a sequence of elements that can be processed functionally, treating data as a potentially infinite or large flow without exposing the underlying storage details. In Java 8 and later, streams offer a consumable-once view of data sources like collections, allowing operations to be applied declaratively rather than imperatively. They support core transformations including map for element projection, filter for selection, and reduce for aggregation, enabling concise expressions for complex data manipulations. Once a terminal operation is invoked, the stream is consumed and cannot be reused, enforcing a single-pass processing model to avoid unintended side effects. Stream pipelines form by chaining operations, where a source stream undergoes intermediate transformations before a terminal operation triggers evaluation. Intermediate operations, such as filter and map, are lazy—they do not execute until a terminal operation like collect or forEach is called, and they return new streams for fluent composition. For instance, the following Java code filters even numbers from a list, squares them, and collects the results into a new list:
java
List<Integer> evenSquares = numbers.stream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * n)
    .collect(Collectors.toList());
This declarative chaining contrasts with explicit loops, emphasizing what to compute over how to compute it. Streams build upon for underlying traversal, exposing an iterator() method to sequentially access elements in a pull-based manner, similar to traditional iterator protocols. For parallel execution, streams leverage spliterators, which extend by supporting ordered splitting of the element source into substreams for concurrent processing on multiple threads. This integration allows to inherit iterator efficiency while adding functional abstractions. The pipeline model excels in expressiveness for bulk operations on large datasets, as defers computation until necessary, and short-circuiting methods like findFirst or anyMatch enable early termination to optimize performance. pipelines can automatically distribute work across cores, improving throughput for tasks without altering the code structure. However, streams' single-use nature requires careful management to avoid recreation overhead for repeated traversals, and the functional paradigm may incur runtime costs from object creation or synchronization in parallel contexts, particularly for small datasets where sequential suffices.

Contrast with Direct Indexing

Direct indexing refers to the method of accessing elements in a collection using offsets, such as array[i] in -based structures, which enables rapid to any provided the is known. This approach is particularly efficient for contiguous memory layouts like , where the size must be predetermined or queried, and the internal representation is directly exposed to the client code. In contrast, iterators provide sequential traversal through a collection's elements without requiring knowledge of the underlying structure, such as whether it is an , , or , thereby promoting and encapsulation. Key differences include iterators' focus on forward-only or controlled , which avoids assumptions about random-access capability or fixed sizing, while direct indexing demands explicit position calculations that can tie code to specific implementations. For instance, iterators support polymorphism by allowing the same traversal logic to work across diverse collection types, whereas indexing often fails for non-contiguous or like sets or graphs. Direct indexing is preferable in performance-critical scenarios involving random access within simple, contiguous collections, such as numerical computations on fixed-size arrays, where it avoids the overhead of iterator objects and method calls. Iterators, however, are more suitable for abstract or heterogeneous collections, like trees or custom aggregates, enabling uniform traversal algorithms that enhance code reusability and maintainability across polymorphic types. A primary drawback of direct indexing is that it breaks encapsulation by exposing the collection's internal details, such as assuming a linear, indexable layout, which makes it unsuitable for non-indexable structures like linked lists where would be inefficient or impossible without additional . This exposure can lead to tighter between client code and the collection's representation, complicating maintenance when the underlying structure changes.

Classification

Categories of Iterators

Iterators are classified into categories based on their capabilities for traversal and access, primarily drawing from the Template Library (STL) model, which has influenced many programming paradigms. These categories form a where more capable iterators can substitute for less capable ones, ensuring flexibility in . The main categories include input, forward, bidirectional, , and output iterators, each defined by specific operations they support. Input iterators provide the minimal level for reading, allowing one-way, single-pass traversal from the beginning to the end of a using increment operations (++it). They support reading elements via dereferencing (*it) but do not permit multi-pass traversal, backward movement, or , making them suitable for algorithms like reading from input streams where the data is consumed once. This category requires only basic operations such as equality comparison (it1 == it2) and advancement, ensuring efficiency for sequential, non-reusable processing. Forward iterators extend input iterators by supporting multi-pass traversal, allowing multiple independent traversals over the same using increment operations (++it). They support reading (and writing in some cases) elements via dereferencing (*it) but do not permit backward movement or , making them suitable for algorithms requiring repeated forward passes, such as . This category maintains the reading capabilities of input iterators while introducing default constructibility and multi-pass support without the overhead of reverse access. Bidirectional iterators extend forward iterators by adding decrement operations (--it), enabling traversal in both directions. They support back-and-forth navigation, which is essential for data structures like doubly-linked lists where elements may need to be inspected or modified in reverse order. This category maintains the reading capabilities of forward iterators while introducing reverse without the overhead of . Random access iterators offer the highest level of flexibility among traditional categories, combining bidirectional traversal with the ability to jump to any position in time using operations (it + n or it - n). This allows efficient indexing-like access (e.g., it) within , as seen in contiguous structures like vectors, providing performance comparable to direct array indexing while adhering to the . Unlike pure indexing, random access iterators still emphasize sequential traversal but with enhanced navigation for algorithms requiring leaps, such as binary search. Output iterators focus on writing rather than reading, supporting forward traversal solely for inserting or assigning values (*it = value) without dereferencing for input. They are designed for single-use write operations, such as inserters in algorithms that build sequences, and do not require or reading capabilities, optimizing for scenarios like stream insertion. Additionally, iterators can be distinguished as (const) or mutable based on whether they allow modification of the pointed-to elements; const iterators return references to constant values, preventing accidental changes, while mutable ones permit writes. In modern programming, especially asynchronous environments, async iterators extend these concepts to handle promises or deferred computations, where the next() method returns a promise resolving to a {value, done} pair. Introduced in ECMAScript 2018, they enable iteration over asynchronous data sources like network streams, supporting forward traversal in non-blocking contexts without altering core synchronous categories.

Types and Use Cases

Tree iterators are specialized mechanisms for traversing hierarchical structures such as trees, enabling systematic access to nodes without exposing the underlying representation. In-order traversal visits nodes in ascending order for search trees, facilitating efficient search and validation of sorted data in algorithms like range queries. traversal processes the root before subtrees, useful for creating tree copies or prefix notations in expression trees within search optimization. Post-order traversal handles subtrees first then the root, essential for tasks like deleting trees or evaluating postfix expressions in algorithms. These iterators find application in XML , where tree traversals navigate document structures to query or transform elements, such as in processing over large XML instances. Filter iterators selectively yield elements from a sequence based on a predicate function, allowing developers to skip irrelevant items during traversal. For instance, a filter might retain only even numbers from a numeric sequence, demonstrating its role in data refinement. These iterators are composable, enabling chained operations like successive filtering and mapping to build complex queries, akin to the iterator model in SQL execution plans for efficient data processing. This composability supports querying scenarios, such as filtering log entries by severity before aggregation in application monitoring systems. Infinite iterators generate unending sequences without termination, contrasting with finite ones by always signaling availability of next elements. The count-up variant produces sequentially increasing values from a starting point, while cycle repeats a finite iterable indefinitely. They serve simulations by modeling continuous processes, such as generating time steps in physics engines or random event streams for methods. In testing, infinite iterators facilitate exhaustive scenario generation, like cycling through test inputs to validate loop behaviors or producing incremental IDs for data pipelines. Beyond specialized types, iterators underpin broader use cases across domains. Database cursors act as iterators over query result sets, enabling row-by-row processing without loading entire datasets into memory, ideal for handling large relational outputs in applications like tools. In user interface rendering, iterators drive loops over collections of components, such as traversing a list of menu items to dynamically generate DOM elements, ensuring efficient updates in event-driven frameworks. For big data processing, Hadoop mappers employ iterator-like mechanisms to sequentially consume input key-value pairs from distributed splits, transforming vast datasets in parallel across clusters. Iterators face challenges in concurrent environments, particularly thread-safety, where multiple threads accessing the same iterator can lead to race conditions or inconsistent states without . Handling mutations during iteration poses risks, such as iterator invalidation when the underlying collection is modified, potentially causing skipped elements, infinite loops, or exceptions like ConcurrentModificationException in . These issues demand careful design, often resolved by using iterators that operate on snapshots or employing locks to protect shared resources.

Implementations in Programming Languages

C++ and Java

In C++, iterators are a core component of the Standard Template Library (STL), providing a uniform interface for traversing sequences in containers like vectors and lists. They are implemented as template classes, such as std::vector<int>::iterator, which allows type-safe iteration over elements without exposing the underlying container's implementation details. The STL defines five iterator categories—InputIterator, OutputIterator, ForwardIterator, BidirectionalIterator, and RandomAccessIterator—each specifying the operations supported, such as reading (*it), advancing (++it), and dereferencing, to enable generic algorithms like std::for_each that work across compatible iterator types. A typical traversal in C++ uses iterators obtained from container methods like begin() and end(), as shown in this example:
cpp
#include <vector>
#include <algorithm>

std::vector<int> vec = {1, 2, 3};
auto it = vec.begin();
while (it != vec.end()) {
    std::cout << *it << " ";
    ++it;
}
// Output: 1 2 3
This approach emphasizes efficiency by allowing fine-grained control over memory access and supporting optimizations in algorithms. Since C++11, range-based for loops (for (auto& elem : vec)) provide a higher-level abstraction over iterators, simplifying common traversals while internally relying on begin() and end(). In C++20, the Ranges library evolves iterators further by introducing range adaptors and views, such as std::views::filter, which compose iterator-like operations without creating intermediate s, enhancing expressiveness and performance for functional-style programming. In Java, iterators are defined through the java.util.Iterator interface, introduced in JDK 1.2, which mandates methods like hasNext(), next(), and remove() for sequential access to collections such as lists and sets. This interface supports forward-only iteration, while the ListIterator sub-interface extends it for bidirectional traversal with additional methods like previous() and add(). Java distinguishes between fail-fast iterators, which throw a ConcurrentModificationException if the underlying collection is structurally modified during iteration (e.g., in ArrayList), and fail-safe iterators, which operate on snapshots to allow concurrent modifications without exceptions (e.g., in CopyOnWriteArrayList). An example of using an iterator in Java for traversal:
java
import java.util.*;

List<String> list = Arrays.asList("a", "b", "c");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    System.out.print(it.next() + " ");
}
// Output: a b c
The enhanced for-loop (introduced in Java 5) integrates seamlessly with iterators via the Iterable interface, allowing concise syntax like for (String s : list) that internally calls iterator(). Java's design prioritizes and over raw performance, contrasting with C++'s category-based flexibility. Since Java 8, iterators link to the Streams API, where collections can be streamed (e.g., list.stream().forEach(System.out::print)), treating iterators as a foundational mechanism for lazy, pipeline-based processing. Comparatively, C++ iterators stress compile-time efficiency and abstraction through categories, enabling zero-overhead in STL algorithms, whereas Java's approach centers on safety and uniformity across the Collections , with mechanisms like fail-fast to prevent subtle bugs in multi-threaded environments. Both languages support bidirectional iterators—akin to C++'s BidirectionalIterator category—for lists, but Java's explicit exception model provides clearer error handling than C++'s on invalidation.

Python and Ruby

In Python, iteration follows the iterable protocol, where an iterable object implements the __iter__ method, which returns an iterator object, and the iterator implements both __iter__ (returning itself) and __next__, which retrieves the next value in the sequence. When no more values are available, __next__ raises a StopIteration exception to signal the end of iteration. Generators provide a concise way to create iterators using the yield keyword, allowing functions to pause and resume execution while maintaining state, which enables lazy evaluation without loading entire sequences into memory. The itertools module extends this capability with efficient iterator-building functions, such as cycle for repeating sequences indefinitely and filterfalse for filtering elements that fail a predicate, forming composable chains for complex data processing. In , the Enumerable supplies traversal and searching methods to collection classes like Array and Hash, provided they implement an each method that yields elements one by one, typically functioning as an internal via block callbacks. The Enumerator class supports both internal and external , allowing lazy of operations like or filtering without immediate evaluation, and can be created using methods such as to_enum or enum_for. Since Ruby , Enumerator::Lazy extends this for deferred computation on infinite or large sequences, overriding methods like map and select to build operation chains that execute only when forced, such as via to_a or . Both languages leverage for iteration, where objects qualify as iterables or iterators if they respond to the expected methods—__iter__/__next__ in or each in —without requiring explicit type declarations or inheritance from specific classes. For example, in , a generator expression like gen = (x**2 for x in [range](/page/Range)(5)) produces an iterator yielding squares lazily, which can be consumed via a or next(gen). In , an can use list.each { |item| puts item } to iterate internally with a , or list.to_enum.each for external control. These features promote simplicity in scripting tasks, such as data processing pipelines, where native lazy evaluation reduces memory usage for large datasets without verbose boilerplate, distinguishing dynamic languages from more rigid systems.

Other Languages

In Scala, the Iterator trait provides a fundamental mechanism for sequential access to elements, featuring core methods hasNext to check for remaining elements and next to retrieve the current one. This trait integrates seamlessly with Scala's functional collections, enabling lazy evaluation through views, which are lightweight wrappers that defer computation until elements are accessed. For instance, a view can be created via collection.view and chained with operations like map or filter without immediate execution, supporting efficient processing of large or infinite sequences. A common idiom is the for-comprehension syntax, such as for (elem <- iterator) yield elem * 2, which leverages the iterator for concise functional iteration. Rust's std::iter::Iterator defines iteration through the next method, which returns Option<T> to yield values until exhaustion, emphasizing to avoid unnecessary computations. Collections implement IntoIterator to convert into iterators, allowing transfer or borrowing as needed, which addresses Rust's strict model by preventing data races in concurrent scenarios. Adapter methods like filter_map combine filtering and transformation, producing a new iterator that applies a to optionally map and include elements, as in iter.filter_map(|x| if x > 0 { Some(x * 2) } else { None }). challenges arise when iterators consume data, but borrowing variants like iter() mitigate this for read-only access. Experimental post-2020 developments include the unstable AsyncIterator (nightly-only as of 2025), which supports asynchronous streams with poll_next for non-blocking I/O in futures-based code. The syntax, for item in iter, consumes or borrows the iterator idiomatically. PHP's Standard PHP Library (SPL) defines the Iterator interface for external , requiring implementations of current, key, next, rewind, and valid to enable foreach compatibility. The base Traversable interface abstracts , allowing classes to support traversal either directly via Iterator or through with IteratorAggregate. Generators, introduced in PHP 5.5, simplify lazy using yield to produce values on-demand without full class implementation, as in function gen() { [yield](/page/Yield) 1; [yield](/page/Yield) 2; }, reducing memory overhead for large datasets. The yield from construct, added in PHP 7.0, enables to sub-generators or traversables for composed flows. These implementations reflect broader trends: Scala's emphasis on influences lazy and composable iterators for declarative code; Rust prioritizes and zero-cost abstractions in , extending to async contexts; PHP evolves web scripting with simplicity to handle dynamic, resource-constrained environments efficiently.

References

  1. [1]
    Iterator Pattern :: CC 410 Textbook
    The iterator pattern is a behavioral pattern that is used to traverse through a collection of objects stored in a container. We explored this pattern in several ...
  2. [2]
    Iterator - Refactoring.Guru
    Iterator is a behavioral design pattern that lets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.) ...Iterator in C++ · Iterator in Go · Iterator in Java · Iterator in Python
  3. [3]
    Iterator (Java Platform SE 8 ) - Oracle Help Center
    Interface Iterator<E> · Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics. · Method ...Classes · ListIterator · PrimitiveIterator
  4. [4]
    Glossary — Python 3.14.0 documentation
    Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most ...
  5. [5]
    Iterators in C++ STL - GeeksforGeeks
    Oct 15, 2025 · An iterator is an object that behaves like a pointer to traverse and access elements of a container. They allow container traversal without ...
  6. [6]
    The Gang of Four (GoF) Iterator | On Iteration - InformIT
    Nov 9, 2009 · The Gang of Four (GoF) Iterator. The Iterator design pattern prescribes interfaces for accessing container elements.
  7. [7]
    Iterator Design Pattern - SourceMaking
    The Iterator provides ways to access elements of an aggregate object sequentially without exposing the underlying structure of the object.
  8. [8]
    [PDF] The History of LISP - Software Preservation Group
    At the ACM annual meeting in early September 1959, McCarthy presented his programming language LISP to the public for the first time [MCC59g]. Nothing is known ...
  9. [9]
    History of Loops | jrott
    Jul 26, 2023 · In Algol there were the full components of structured programming including for and while loops that basically are the same as for and while ...
  10. [10]
    [PDF] The Birth of Object Orientation: the Simula Languages - UiO
    In 1962 Kristen Nygaard, KN, initiated a project for the development of a discrete event simulation language, to be called Simula. At the time KN.Missing: iteration | Show results with:iteration
  11. [11]
    [PDF] A History of CLU - CSAIL Publications - MIT
    Dec 6, 1973 · In the early and mid l970's, it led to the development of new programming languages, most notably CLU and Alphard. These language designs were ...
  12. [12]
    A history of CLU | History of programming languages---II
    CLU was the first implemented programming language to provide direct linguistic support for data abstraction. ... iterators, and its parameterized types.
  13. [13]
    History of patterns - Refactoring.Guru
    In 1994, they published Design Patterns: Elements of Reusable Object-Oriented Software, in which they applied the concept of design patterns to programming.
  14. [14]
    Standard Template Library, STL
    History. 1979: the idea of generic programming (Alex Stepanov); 1987: Ada library (Stepanov and Dave Musser); 1994: C++ library (Stepanov, Musser and Meng Lee).
  15. [15]
    What's New in Python 2.2 — Python 3.14.0 documentation
    Author, A.M. Kuchling,. Introduction: This article explains the new features in Python 2.2.2, released on October 14, 2002. Python 2.2.2 is a bugfix release ...What's New In Python 2.2 · Peps 252 And 253: Type And... · Pep 255: Simple GeneratorsMissing: date | Show results with:date
  16. [16]
    History of C#: versions, .NET, Unity, Blazor, and MAUI - PVS-Studio
    Apr 28, 2025 · Let's take a peek at the tangled history of its evolution from version to version and explore the different tools that power modern C# development.Same Year: . Net Framework · 2005: C# 2.0 · 2015: C# 6.0
  17. [17]
    Design Patterns: Elements of Reusable Object-Oriented Software
    30-day returnsOct 31, 1994 · The authors begin by describing what patterns are and how they can help you design object-oriented software. They then go on to systematically ...
  18. [18]
    Iterator Design Pattern - GeeksforGeeks
    Oct 26, 2025 · The Iterator design pattern is a behavioral design pattern that provides a way to access the elements of an aggregate object (like a list) sequentially
  19. [19]
    Iterator in Java / Design Patterns - Refactoring.Guru
    Iterator is a behavioral design pattern that allows sequential traversal through a complex data structure without exposing its internal details.
  20. [20]
  21. [21]
    [PDF] Design Patterns Elements of Reusable Object-Oriented Software
    Iterator (257) Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. Mediator (273) Define an ...
  22. [22]
    [PDF] The Essence of the Iterator Pattern
    The ITERATOR pattern gives a clean interface for element-by-element access to a collection, in- dependent of the collection's shape.
  23. [23]
    Iterators: Signs of Weakness in Object-Oriented Languages Henry G ...
    Iterators are a 1980's version of the 1950's concept of generators. A ... Unfortunately, our lazy evaluation implementation uses "upward funargs ...
  24. [24]
    [PDF] Why Functional Programming Matters
    Because lazy evaluation's power depends on the programmer giving up any direct control over the order in which the parts of a program are executed, it would ...
  25. [25]
    Generators and the replicator control structure in the parallel ...
    Iterators are functions which can maintain their data and control state after they return a value. ICON [GG83] provides limited control backtracking, generators ...
  26. [26]
    Package java.util.stream - Oracle Help Center
    Package java.util.stream. Classes to support functional-style operations on streams of elements, such as map-reduce transformations on collections.
  27. [27]
    Lesson: Aggregate Operations (The Java™ Tutorials > Collections)
    Internal iteration does not have this limitation. It can more easily take advantage of parallel computing, which involves dividing a problem into subproblems, ...<|control11|><|separator|>
  28. [28]
    Stream (Java Platform SE 8 ) - Oracle Help Center
    For further API reference and developer documentation, see Java SE Documentation. That documentation contains more detailed, developer-targeted descriptions ...Classes · Package java.util.stream · Uses of Interface java.util... · IntStream
  29. [29]
    Streams vs. Loops in Java - Baeldung
    Jan 8, 2024 · Both streams and loops have their strengths and weaknesses. Streams offer a more functional and declarative approach, enhancing code ...
  30. [30]
    Should I always use a parallel stream when possible? - Stack Overflow
    Dec 4, 2013 · A parallel stream has a much higher overhead compared to a sequential one. Coordinating the threads takes a significant amount of time.
  31. [31]
    When to Use a Parallel Stream in Java | Baeldung
    May 17, 2021 · Parallel streams enable us to execute code in parallel on separate cores. The final result is the combination of each individual outcome.
  32. [32]
    Iterators | Microsoft Learn
    Jan 28, 2022 · An output iterator X can iterate forward over a sequence by using the ++ operator, and can write an element only once, by using the * operator.
  33. [33]
    Iterator - CPlusPlus.com
    All standard containers support at least forward iterator types. Bidirectional iterators are like forward iterators but can also be iterated through backwards.Random-access iterator · Std::iterator · Std::forward_iterator_tag · Std::next
  34. [34]
    AsyncIterator - JavaScript - MDN Web Docs
    Oct 30, 2025 · An AsyncIterator object is an object that conforms to the async iterator protocol by providing a next() method that returns a promise fulfilling to an iterator ...
  35. [35]
    tc39/proposal-async-iteration: Asynchronous iteration for JavaScript
    Jan 26, 2022 · An async iterator is much like an iterator, except that its next() method returns a promise for a { value, done } pair. As noted above, we must ...Tc39/proposal-Async-Iteratio... · Async Iterators And Async... · Async Generator Functions
  36. [36]
    16. Trees and their Iterators | CS 2110
    We can define three different iterators to produce the elements of a binary tree according to these three traversal orders, a pre-order iterator, an in-order ...Missing: programming: | Show results with:programming:
  37. [37]
    Iterative Preorder, Inorder and Postorder Traversal Using Stack
    We can easily implement recursive binary tree traversals (preorder, inorder, and postorder) iteratively using a stack. We need to understand the flow of ...
  38. [38]
    Preorder vs Inorder vs Postorder - GeeksforGeeks
    Jul 23, 2025 · Preorder Traversal, the root node is visited first, followed by the left and right subtrees. · Inorder Traversal starts with the left subtree, ...
  39. [39]
    Iterators and Iterables in Python: Run Efficient Iterations - Real Python
    Jan 6, 2025 · Iterators control loops, allowing you to traverse arbitrary data containers one item at a time. Iterables, on the other hand, provide the data that you want to ...The Iterable Protocol · Unpacking Iterables · Comparing Iterators Vs...
  40. [40]
    SQL Query Execution: Understanding the Iterator Model - Medium
    every operation implements the same iterator ...
  41. [41]
    Filtering and Mapping with SPL Iterators | Mark Baker's Blog
    Jan 5, 2020 · The basic FilterIterator accepts the Iterator that we want to filter as its constructor argument; then as we iterate over the records, it calls ...
  42. [42]
    Infinite Iterators in Python: itertools.count, cycle, repeat | note.nkmk.me
    Aug 19, 2023 · itertools.count() creates an iterator that counts up or down infinitely. By default, it starts at 0 and increases by 1.
  43. [43]
    Infinite Iterators in Python - GeeksforGeeks
    Jul 12, 2025 · Python provides three types of infinite iterators - count(start, step): This iterator starts printing from the “start” number and prints infinitely.
  44. [44]
    Python Infinite Iterators - Complete Guide - ZetCode
    Mar 29, 2025 · Infinite iterators shine when producing continuous streams of random data, ideal for testing or simulation scenarios. random_data.py. import ...
  45. [45]
    Exploring Infinite Iterators in Python's itertools - KDnuggets
    Oct 10, 2023 · These infinite iterators are extremely helpful in scenarios when we need to work with streams of data. The “count”, “cycle” and “repeat ...
  46. [46]
    What is a Database Cursor? Types, Uses & Examples Explained
    Jun 20, 2025 · A cursor is a control structure that allows you to retrieve and manipulate rows in a result set one at a time, offering precise row-level access and navigation.
  47. [47]
    [PDF] MapReduce: Simplified Data Processing on Large Clusters
    MapReduce is a programming model and an associ- ated implementation for processing and generating large data sets. Users specify a map function that ...
  48. [48]
    Iterating atomically - Jon Skeet's coding blog
    Oct 23, 2009 · The question asks how to create a thread-safe iterator – one that can be called from multiple threads.<|separator|>
  49. [49]
    What is iterator invalidation - a practical guide for 2025 - Shadecoder
    Oct 16, 2025 · Identify the container and its invalidation contract. · Decide whether you need stable handles. · Use safe iteration idioms. · Minimize iterator ...<|control11|><|separator|>
  50. [50]
    Fail-Safe vs Fail-Fast: Which Java Iterator to Use? - Index.dev
    Jun 3, 2025 · Fail-fast throws errors on concurrent changes, while fail-safe uses snapshots to avoid them. This guide helps you choose the right one for robust Java apps.Fail-Safe Vs Fail-Fast... · Mechanism And Implementation · How Our Custom...<|control11|><|separator|>
  51. [51]
  52. [52]
  53. [53]
    itertools — Functions creating iterators for efficient looping — Python ...
    The itertools module provides fast, memory-efficient iterator building blocks for efficient looping in Python, forming an 'iterator algebra'.
  54. [54]
    module Enumerable - RDoc Documentation - Ruby-Doc.org
    Returns whether every element meets a given criterion. If self has no element, returns true and argument or block are not used.Missing: mixin | Show results with:mixin
  55. [55]
    class Enumerator::Lazy - Documentation for Ruby 2.0.0
    Creates a new Lazy enumerator. When the enumerator is actually enumerated (e.g. by calling force), obj will be enumerated and each value passed to the given ...
  56. [56]
  57. [57]
    Iterators | Collections - Scala Documentation
    An iterator is not a collection, but rather a way to access the elements of a collection one by one. The two basic operations on an iterator it are next and ...
  58. [58]
    Views | Collections - Scala Documentation
    A view is a special collection that represents a base collection, implementing transformers lazily. It's created using `view` method and accessed via `xs.view`.
  59. [59]
    Iterator in std - Rust Documentation
    An iterator is a trait for dealing with iterators. It advances and returns the next value using the `next()` method, returning `None` when finished.
  60. [60]
    IntoIterator in std::iter - Rust Documentation
    By implementing IntoIterator for a type, you define how it will be converted to an iterator. This is common for types which describe a collection of some kind.
  61. [61]
    FilterMap in std::iter - Rust Documentation
    An iterator that uses f to both filter and map elements from iter. This struct is created by the filter_map method on Iterator. See its documentation for more.
  62. [62]
    AsyncIterator in std::async_iter - Rust Documentation
    A trait for dealing with asynchronous iterators. This is the main async iterator trait. For more about the concept of async iterators generally, please see the ...
  63. [63]
    Iterator - Manual - PHP
    The Iterator interface (PHP 5, PHP 7, PHP 8) Introduction Interface for external iterators or objects that can be iterated themselves internally.Iterators · Traversable · IteratorAggregate
  64. [64]
    Traversable - Manual - PHP
    The Traversable interface detects if a class is usable with `foreach` and is the base interface for all traversable classes, implemented by `IteratorAggregate` ...
  65. [65]
    Generators overview - Manual - PHP
    Generators provide an easy way to implement simple iterators without the overhead or complexity of implementing a class that implements the Iterator interface.
  66. [66]
    Generator syntax - Manual - PHP
    Yielding by reference ¶. Generator functions are able to yield values by reference as well as by value. This is done in the same way as returning references ...