Fast enumeration extension proposal


I'd like to propose an extension to the fast enumeration behaviour for Objective-C 2. This allows you to efficiently iterate over objects in a collection, but it would also be convenient in a great many cases to use the same mechanism to iterate over things that contain collections of primitive types, such as strings. Indeed, the iteration method is conceptually very similar to the -getBytes:range: and getCharacters:range: methods on NSData and NSString, respectively.

I've attached a diff (please do not commit as is!) which give a proof of concept implementation of a generalisation of fast enumeration to permit this. This generalises the method use for fast enumeration to this:

- (NSUInteger)countByEnumeratingWithState: (NSFastEnumerationState*)state
                                   buffer: (void*)stackbuf
                                     type: (const char*)type
                                    count: (NSUInteger)len

This replaces the the object:(id*) parameter with two arguments; one a pointer to the buffer, the other an Objective-C type encoding of a single element in the array. If you call it with something like this:

for (unichar a in @"Foobar!")

The first parameter will be an array of len unichars, the third element will be "S" (the type encoding of unichar, which is a typedef for unsigned short).

I could add this as a GNU extension, but it would be more useful if it were supported by Apple as well. Note that this should have no impact on existing code: currently both clang and GCC raise an error with non-object element types, and my diff generates the old method for object return types.

I'm also tempted to suggest generalising it still slightly further by permitting a range for enumeration to be specified (this would, of course, only be relevant for ordered collections), as this currently requires falling back to very slow enumeration. I'm not sure what the best syntax for this would be though, maybe something like:

for (id a in array[1..30])

for (id a in array range 1,30)

Something else?

Comments, (constructive) criticisms, and suggestions welcome,


fenum.m (1.89 KB)

clang.diff (3.68 KB)

Just some quick feedback.

The Fast Enumeration protocol was directly driven by the need to simplify and improve access to the dominant-by-choice "collection" in Cocoa: the NSArray. We built it to be blindingly fast. And yet we also built in knowledge of particular protocols, which have Cocoa expression instead of ObjC, so its slightly sullied from a language viewpoint in that the ObjC protocol isn't widely used, but a Cocoa equivalent is.

The issue with extending the existing protocol, as you propose, is that there are an arbitrary number of extensions possible, and each would require adoption by appropriate classes. Protocols are much heavier than method with blocks, and so we like the lighter weight on principle.

Blocks are very efficient, but they do require a function call cost per item which, well, can be a lot depending on the application.

Ripping through unichars would seem like possibly something done so often, and with somewhat tricky API, to warrant special treatment, as you suggest. However, unichars aren't what you think they are, in that several unichars are needed to represent some concepts, there are sex-change markers, etc. and hence the very studied complexity of the NSString implementation. So I honestly think your proposal would run into conceptual difficulties if presented within Apple's Cocoa engineering team, as an Apple Developer sonar request. This forum is not suitable for those discussions.

Other suggestions for extensions to NSFastEnumeration have been to rip through language arrays, for example. This is wonderful if array size information is available to the compiler, which on occasion it is, then formal language treatment offers a significantly better programmer experience since it reduces or eliminates bounds errors. Supplying bounds by hand offers no language benefit other than a fancy syntax to distinguish a special use case - not really interesting. However, more on the for ( int a in intarray) line of thinking without the need for new protocols is interesting. That might, in fact, meet your criteria.

Since this is a quick reply there is of course the possibility I haven't thought deeply enough about your suggestion, so please feel free to sign up as a developer and continue to argue your case some more when it involves Cocoa.