[swift-evolution] [Proposal] Change guarantee for GeneratorType.next() to always return nil past end
swift-evolution at haravikk.me
Thu Mar 3 02:41:51 CST 2016
+1 from me on the grounds that I had no idea that this was an expectation of GeneratorType.next(), so yeah; all my generators currently return `nil` infinitely past the end. Does anyone know the history of this requirement? Perhaps it’s a newer one and I didn’t notice it being added?
The only advantage to a failure vs continuing nil that I can think of is if the generator is returning an optional type anyway; if the developer doesn’t check correctly for nil from the generator vs a stored value of nil then they could end up with an infinite loop, but this seems unlikely given that they’d be dealing with a type of Element?? rather than Element?, so whatever they’re doing with the results should fail due to type mismatches anyway.
So yeah, there’s possibly (and I stress possibly) a narrow case in which failure might catch a bug, but in most cases the optional behaviour should be enough, and the generator itself should be handling indices correctly internally to prevent issues with stepping past .endIndex etc.
> On 3 Mar 2016, at 06:47, Patrick Pijnappel via swift-evolution <swift-evolution at swift.org> wrote:
> Currently GeneratorType.next() requires callers to not call next() after it has returned nil once, even encouraging a preconditionFailure() if this is violated:
> /// - Requires: `next()` has not been applied to a copy of `self`
> /// since the copy was made, and no preceding call to `self.next()`
> /// has returned `nil`. Specific implementations of this protocol
> /// are encouraged to respond to violations of this requirement by
> /// calling `preconditionFailure("...")`.
> However, all 28 GeneratorTypes in the standard library actually do return nil on repeated calls past the end.
> Silent corner case
> Because basically all generators keep returning nil, it's not unlikely people will write their code based on the assumption it will always return nil (breaking the requirement) and that will almost always work – until someone passes in a GeneratorType that actually does raise the recommended preconditionFailure(). It becomes a silent corner case.
> Adds caller burden
> To avoid breaking the requirement, the caller will not uncommonly have to track extra state and branch (e.g. keep a done/atEnd boolean). For example the UTF-8 & UTF-16 decoders do this (incidentally introducing an extra branch into a hot code path), while the UTF-32 decoder doesn't actually check – passing the requirement on to its caller (without this being documented). From personal experience implementing several custom generators I've found that respecting the requirement invariably adds complexity to the implementation.
> Doesn't prevent bugs
> There seems to be little advantage to having it crash on past-the-end calls to next(). So far I haven't seen any examples where not crashing would silently hide a bug – and again even if there was it wouldn't help much considering almost no generators actually do crash.
> Change the guarantee for GeneratorType.next() to keep returning nil indefinitely after it has been exhausted.
> swift-evolution mailing list
> swift-evolution at swift.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-evolution