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

Patrick Pijnappel patrickpijnappel at gmail.com
Thu Mar 3 05:24:27 CST 2016

Hmm I see.

Do we have any example cases where returning nil repeatedly would require
extra branches or state?

The generators in the standard library don't (*) – the usual pattern is
either of the following:
- 1) Check state if we're at end, if so return nil 2) get return value 3)
advance state. Since the state is not mutated before returning nil,
repeating nil is automatic.
- 1) Call next() on one or more wrapped generators 2) return some
transformation of that. If the wrapped generators repeat nil, repeating nil
is also automatic for the wrapper.

If you would have a generator setup that doesn't automatically repeat nil,
omitting a nil-repeat check might be dangerous considering the risk other
code hadn't considered the case.

(*) StrideThroughGenerator & ZipGenerator have a done flag, but need these
even without repeating nil. JoinGenerator has an .End state but actually
doesn't have to – even to repeat nil.

On Thu, Mar 3, 2016 at 8:12 PM, Dmitri Gribenko <gribozavr at gmail.com> wrote:

> On Wed, Mar 2, 2016 at 10:47 PM, Patrick Pijnappel via swift-evolution
> <swift-evolution at swift.org> wrote:
> > Situation
> > 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("...")`.
> I'd like to add more context to this discussion.  We added this
> requirement a while ago.  [1]  The reason for introducing it was not
> an attempt to flag bugs in client code.  Rather, we were not convinced
> that all generators can return nil repeatedly without loss of
> efficiency or extra storage burden.
> [1]
> https://github.com/apple/swift/commit/304b4f33ae74a5abd09da485bbc435dfa2ade522
> and rdar://problem/17392226
> > Adds caller burden
> > To avoid breaking the requirement, the caller will not uncommonly have
> to track extra state and branch
> I would actually say the opposite -- running a non-trivial algorithm
> on generators is a very uncommon thing to do.  The 99% use case for
> generators is implicit usage from the for-in loop.  This is why
> allowing generators to be as simple as possible and pushing the
> requirement for extra branches into non-trivial algorithms made sense
> for us when we introduced this requirement.
> > 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
> This is what concerns me the most about the current rules.
> Dmitri
> --
> main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
> (j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160303/373a9230/attachment.html>

More information about the swift-evolution mailing list