# How Fast Enumeration Works in Mulle-ObjC: NSFastEnumeration Protocol and Compiler Internals

> Discover how Mulle-ObjC optimizes fast enumeration using the NSFastEnumeration protocol and compiler transformations. Learn how mutation detection enhances stability. Read now!

- Repository: [mulle-objc/mulle-objc-runtime](https://github.com/mulle-objc/mulle-objc-runtime)
- Tags: internals
- Published: 2026-03-07

---

**Mulle-ObjC implements fast enumeration through the standard `NSFastEnumeration` protocol, where the compiler transforms `for-in` loops into optimized C `while`-loops that repeatedly invoke `countByEnumeratingWithState:objects:count:`, while the runtime provides the `mulle_objc_enumeration_mutation` helper to detect and abort on collection mutations during iteration.**

Fast enumeration provides optimized, safe iteration over collections in Objective-C. The `mulle-objc/mulle-objc-runtime` repository implements this mechanism exactly like the Apple Objective-C runtime, relying on protocol adoption and compiler-generated loop structures rather than runtime-provided enumerators. This approach delegates the actual batching logic to the collection classes while centralizing mutation safety checks within the runtime core.

## The NSFastEnumeration Protocol

Collections that support fast enumeration in Mulle-ObjC must adopt the `NSFastEnumeration` protocol and implement a single required method. This method is responsible for returning batches of objects to the caller and maintaining iteration state across multiple invocations.

The method signature follows the standard Objective-C convention:

```objc
- (uintptr_t) countByEnumeratingWithState:(NSFastEnumerationState *)state
                                 objects:(id *)buffer
                                   count:(uintptr_t)len;

```

The `state` parameter tracks the current position in the collection, the `buffer` provides temporary storage for object pointers, and `len` indicates the maximum number of objects the buffer can hold. Implementations must update `state->itemsPtr` to point to the buffer and return the actual number of objects placed in the buffer.

## Compiler Transformation of for-in Loops

The Mulle-ObjC compiler (mulle-objc-clang) does not rely on runtime magic to execute `for-in` syntax. Instead, it lowers the Objective-C syntax into equivalent C code that manages an `NSFastEnumerationState` structure and a temporary buffer.

A loop such as:

```objc
for (Bar *bar in foo)
    [bar print];

```

Transforms roughly into the following pseudo-code pattern:

```c
NSFastEnumerationState state = {0};
Bar *buffer[16];
uintptr_t count;
while ((count = [foo countByEnumeratingWithState:&state
                                          objects:buffer
                                            count:sizeof(buffer)/sizeof(*buffer)]) != 0)
{
    for (uintptr_t i = 0; i < count; ++i)
    {
        Bar *bar = (Bar *)buffer[i];
        [bar print];
    }
}

```

This generated code repeatedly calls the collection's `countByEnumeratingWithState:objects:count:` method until it returns zero, indicating that no objects remain. The buffer size of 16 is typical, though the compiler may choose different sizes based on optimization settings.

## Mutation Detection and Safety

Fast enumeration must abort if the underlying collection mutates during iteration. Mulle-ObjC provides a dedicated runtime function to handle this failure scenario, ensuring consistent error reporting across all collection types.

The runtime exposes `mulle_objc_enumeration_mutation` in [`src/mulle-objc-fastenumeration.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-fastenumeration.h) and implements it in [`src/mulle-objc-fastenumeration.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-fastenumeration.c):

```c
MULLE_C_NO_RETURN void
   mulle_objc_enumeration_mutation( void *collection)
{
   mulle_objc_universe_fail_inconsistency(
        NULL,
        "collection %p mutated while enumerating",
        collection);
}

```

When a collection's implementation detects that its internal structure has changed (typically by comparing a stored mutations value against `state->mutationsPtr`), it invokes this function. The runtime immediately aborts the program with a clear "enumeration mutated" error message, preventing undefined behavior from inconsistent iteration state.

## Concrete Implementation Example

The repository includes a functional demonstration in `test-compiler/fastenumeration/fastenumeration.m`, showing how to properly implement `NSFastEnumeration` with mutation tracking.

The example implementation fills a buffer with references to `self` and sets up the mutations pointer for safety detection:

```objc
- (uintptr_t) countByEnumeratingWithState:(NSFastEnumerationState *)rover
                                 objects:(id *)buffer
                                   count:(uintptr_t)len
{
    uintptr_t remain = 20 - rover->state;
    if (!remain) return 0;
    if (remain < len) len = remain;

    rover->state    += len;
    rover->itemsPtr  = buffer;
    for (id *end = buffer + len; buffer < end; ++buffer) *buffer = self;
    rover->mutationsPtr = &rover->extra[4];   // mutation detection
    return len;
}

```

This implementation returns batches of objects until exhausting a fixed set of 20 items, assigning the mutations pointer to enable runtime mutation checks. If the test modifies the collection during the `for-in` loop, the program triggers `mulle_objc_enumeration_mutation` and aborts.

## Key Source Files

Understanding fast enumeration in Mulle-ObjC requires familiarity with these specific source locations:

- **[`src/mulle-objc-fastenumeration.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-fastenumeration.h)** – Declares the `mulle_objc_enumeration_mutation` function prototype.
- **[`src/mulle-objc-fastenumeration.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-fastenumeration.c)** – Implements the mutation-abort helper that terminates the program on concurrent modification.
- **`test-compiler/fastenumeration/fastenumeration.m`** – Provides a complete working example of a class implementing `NSFastEnumeration` with proper state management.
- **[`include/mulle-objc-runtime/mulle-objc-runtime.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/include/mulle-objc-runtime/mulle-objc-runtime.h)** – Exposes the public API consumed by fast-enumerable collections.
- **[`src/mulle-objc-runtime-standalone.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-runtime-standalone.c)** – Contains the core method-dispatch engine that forwards the `countByEnumeratingWithState:objects:count:` selector to the object's implementation.

## Summary

- Mulle-ObjC fast enumeration relies on the `NSFastEnumeration` protocol and the `countByEnumeratingWithState:objects:count:` method signature.
- The compiler transforms `for-in` loops into `while`-loops managing an `NSFastEnumerationState` structure and a temporary object buffer.
- Mutation detection uses the `mulle_objc_enumeration_mutation` function in [`src/mulle-objc-fastenumeration.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-fastenumeration.c), which aborts execution if the collection changes during iteration.
- The runtime delegates actual enumeration logic to the collection's protocol implementation rather than providing a built-in enumerator class.

## Frequently Asked Questions

### What protocol must collections adopt to support fast enumeration in Mulle-ObjC?

Collections must adopt the `NSFastEnumeration` protocol and implement the `countByEnumeratingWithState:objects:count:` method. This method receives a state structure and buffer pointer, returning the number of objects placed in the buffer for each batch.

### How does Mulle-ObjC detect mutations during fast enumeration?

The generated loop code monitors a `mutationsPtr` within the `NSFastEnumerationState` structure. If the collection detects internal changes during iteration, it triggers the `mulle_objc_enumeration_mutation` function defined in [`src/mulle-objc-fastenumeration.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-fastenumeration.c), causing the runtime to abort with an inconsistency error.

### Does the Mulle-ObjC runtime provide the fast enumeration loop implementation?

No, the runtime does not contain a special enumerator implementation. The compiler generates the loop structure, and the runtime simply dispatches the `countByEnumeratingWithState:objects:count:` selector to the object's implementation, providing only the mutation detection helper for safety.

### Where can I find example implementations of NSFastEnumeration in the Mulle-ObjC repository?

The `test-compiler/fastenumeration/fastenumeration.m` file contains a complete working example demonstrating a fast-enumerable class with proper state management, buffer filling, and mutation pointer setup for concurrent modification detection.