[swift-evolution] [Proposal] Change guarantee for GeneratorType.next() to always return nil past end

Kevin Ballard kevin at sb.org
Sun Mar 6 20:10:54 CST 2016

On Sat, Mar 5, 2016, at 10:35 PM, Brent Royal-Gordon wrote:
> >> I think it will be far easier to write generic tests of any generator than it will be to write generic tests of any function that *uses* a generic generator.
> >> 
> >> (Although I suppose you could assist in that testing by writing a wrapper around any sequence/collection/generator which enforces all rules as strictly as possible.)
> > 
> > You could always just test the behavior of the FuseGenerator wrapping it, if you really want to be able to rely on always-returning-nil behavior. But I'm not sure what tests you'd write that even hits this case, except for a test that's designed specifically to test the post-nil behavior (which we've already established isn't necessary to check for arbitrary generators if GeneratorType leaves that as implementation-defined).
> The fuse generator wouldn't do what I'm talking about. What I mean is that it might be useful for testing purposes to be able to wrap a collection/sequence in a StrictCollection/StrictSequence (with corresponding StrictGenerators, StrictIndexes,etc.) which would do things like:
> * Detect if you copy a generator and then use both copies
> * Detect if you call next() on a generator after it returns nil
> * StrictCollection only: Invalidate all indices retrieved before any mutation
> * StrictSequence only: Prevent you from making a generator more than once
> The idea is that, when you're writing a piece of code that's generic on any collection or sequence type, your unit tests could pass in a StrictCollection/StrictSequence-wrapped version of whatever your actual data is, and if your code doesn't crash you can be pretty sure it's not violating any of those protocols' unevenly enforced requirements.

If you're working with a generic collection/sequence, then it's still perfectly reasonable to detect if you call next() on a generator after it returns nil regardless of how the post-nil behavior is defined. After all, if you're working with a generic sequence/generator, and the post-nil behavior is implementation-defined, then your generic code probably doesn't want to invoke post-nil behavior because it doesn't know what will happen. Defining post-nil behavior as always returning nil simply lets you skip this check in your StrictGenerator, but having post-nil behavior being implementation-defined certainly doesn't make testing this any harder.

And if you want to use this same StrictSequence/StrictGenerator when you're using a sequence/generator that you explicitly know defines post-nil behavior as something useful (or if you're writing a sequence/generator adaptor where your adaptor's post-nil behavior naturally matches the underlying generator's, and you want to test your code with clients that may be relying on specific post-nil behavior) then you can parameterize your StrictSequence/StrictGenerator with a flag that tells it whether to check the post-nil behavior. In fact, you may want to do that anyway to enable disabling of any of the checks, because it's certainly possible for a concrete SequenceType/GeneratorType implementation to relax any of these requirements you're checking. For example, a specific GeneratorType implementation could explicitly document that copying the generator is safe and both copies then yield the same sequence of elements.

-Kevin Ballard

More information about the swift-evolution mailing list