<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body><div>On Thu, Mar 3, 2016, at 03:24 AM, Patrick Pijnappel via swift-evolution wrote:<br></div>
<blockquote type="cite"><div dir="ltr"><div>Hmm I see.<br></div>
<div>&nbsp;</div>
<div>Do we have any example cases where returning nil repeatedly would require extra branches or state?<br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>Yes. My proposed .takeWhile() and .dropWhile() sequence adaptors (<a href="https://github.com/apple/swift-evolution/pull/95">https://github.com/apple/swift-evolution/pull/95</a>) would hit this case. Both of those adaptors would need to keep around extra state and in order to keep returning nil.<br></div>
<div>&nbsp;</div>
<div>My preferred solution for this case is to add a new Generator adaptor called a FuseGenerator, with a convenience method .fuse(). All this adaptor does is include the extra state in order to ensure it keeps returning nil forever. This way Generators don't have to keep the state for that guarantee, and the majority case where client codes doesn't rely on this guarantee doesn't need the check either, and in the rare case where this guarantee is important all the user has to do is call .fuse() on the generator and use the result of that instead.<br></div>
<div>&nbsp;</div>
<div>All that said, I would be strongly in favor of dropping the language about triggering a precondition failure. I'd prefer to leave it as implementation-defined behavior, which an encouragement to keep returning nil if it's easy to do so. A benefit of this is Generators could opt to explicitly define their post-nil behavior, e.g. TakeWhileGenerator could explicitly document that after it has returned nil, subsequent calls to .next() will continue to consume the underlying generator and return another stream of elements terminating in `nil` (with the caveat that if the underlying generator is exhausted then behavior depends on the underlying generator's post-nil behavior). Granted, this probably isn't useful in most cases, but it could be useful upon occasion as a way to lazily split a sequence without building intermediate data structures (assuming that the underlying generator is fused or defines its post-nil behavior as returning nil forever).<br></div>
<div>&nbsp;</div>
<div>FWIW, Rust uses precisely the solution I've described here (and in fact I'm responsible for its std::iter::Fuse iterator). It defines Iterator::next() such that calling .next() after it has returned None may or may not return more elements (but Iterators are not supposed to assert in this case, they should always return something). And it has the .fuse() convenience method that returns a std::iter::Fuse iterator that provides the always-returns-None guarantee. And in practice, almost nobody ever has to actually use .fuse(), since almost nobody writes algorithms that cares about the behavior after next() returns None (and in the rare case where they do, they're typically using some concrete Iterator that has defined behavior, as opposed to working on arbitrary Iterators).<br></div>
<div>&nbsp;</div>
<div>-Kevin Ballard</div>
</body>
</html>