<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Hi Tim,</div><div class=""><br class=""></div><div class="">After having a quick conversation with Dave, here is the question I should have asked right away: can you share the typical problem you are solving with your overload of the `sequence(first:next:)` function?</div><div class=""><br class=""></div><div class="">Max</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Aug 20, 2016, at 2:26 AM, Tim Vermeulen <<a href="mailto:tvermeulen@me.com" class="">tvermeulen@me.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">What you’re saying makes sense, and I might not have brought this up in the first place if `first.map { sequence(first: $0, next: next } ?? []` worked. The main annoyance is that the best solution (currently) seems to be to copy the source code and make a change.</div><div class=""><br class=""></div><div class="">(cc-ing Jordan Rose because of a related swift-users thread) This might be a bit of a stretch, but can’t Swift upcast sequences to AnySequence implicitly, like is done with AnyHashable? That would make `first.map { sequence(first: $0, next: next } ?? []` instantly valid, I think. There’s also something to be said for consistency between type erasers. (I’m not necessarily talking about Swift 3)</div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 20 Aug 2016, at 02:22, Max Moiseev <<a href="mailto:moiseev@apple.com" class="">moiseev@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Hi Tim,</div><div class=""><br class=""></div><div class="">I still believe that having 2 termination conditions is wrong. But I guess we need a tie breaker here, someone with a strong opinion about the problem.</div><div class="">As Kevin mentioned we are very late in the release process, so waiting for another opinion for a day or two won’t change anything, really.</div><div class=""><br class=""></div><div class="">Meanwhile, I played a little bit with an idea of making `first.map { sequence(first $0, next: next} ?? []` work. </div><div class="">Turns out, if we add an `ExpressibleByArrayLiteral` protocol conformance to the `UnfoldSequence`, this snippet will compile just fine. One downside is that the `ExpressibleByArrayLiteral` protocol allows creating non-empty sequences as well, which does not make sense for the `UnfoldSequence`.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Max</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Aug 19, 2016, at 3:48 PM, Tim Vermeulen via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On 19 Aug 2016, at 19:48, Kevin Ballard <<a href="mailto:kevin@sb.org" class="">kevin@sb.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class=""><div class="">AFAIK this issue has never been discussed with sequence(first:next:) before. It certainly wasn't brought up during review.<br class=""></div><div class=""><br class=""></div><div class="">As for my opinion, I'm really not sure. I was going to point out that right now sequence(first:next:) guarantees that the first element of the resulting sequence is the value provided as "first", but it occurs to me that if you treat the nil result from next() as an element, then this still holds true. So I guess my biggest worry is this change will make it harder to use sequence(first:next:) to produce sequences of optional values.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I don’t think producing sequences of optional values would really be a problem, because type inference will figure this out based on whether you treat the argument to the `next` closure as an optional or not. And if you only do things in `next` that work both with optionals and non-optionals (very unlikely), you can always manually specify the type of the sequence.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><div class="">So I guess I'm ambivalent, and would prefer to defer to the wisdom of the Swift core team on this matter.<br class=""></div><div class=""><br class=""></div><div class="">That said, didn't the deadline for source-breaking changes already come and go?</div><div class=""><br class=""></div><div class="">-Kevin Ballard</div><div class=""><br class=""></div><div class="">On Fri, Aug 19, 2016, at 10:37 AM, Max Moiseev wrote:<br class=""></div><blockquote type="cite" class=""><div class="">+ Erica, Kevin, as the authors of the original proposal.<br class=""></div><div class=""><br class=""></div><div class="">Do you remember the problem of non-emptiness being discussed before? And if not, what’s your opinion on the proposed change?<br class=""></div><div class=""><br class=""></div><div class="">Thanks,<br class=""></div><div class=""><div class="">Max<br class=""></div><div class=""><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Aug 19, 2016, at 7:53 AM, Tim Vermeulen <<a href="mailto:tvermeulen@me.com" class="">tvermeulen@me.com</a>> wrote:<br class=""></div><div class=""><br class=""></div><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;"><div class="">Hi Max, thanks for having a look.<br class=""></div><div class=""><br class=""></div><div class="">A big part of why I’m not really happy with the current implementation is that the function always produces a nonempty sequence, though the compiler doesn’t know it. `sequence(first: first, next: next).last` returns an optional, even though it can’t possibly be nil. The same goes for something like `sequence(first: 5, next: { $0 * 3 }).first(where: { $0 > 1000 })`, because the sequence is infinite, which means `first(while:)` will either keep running forever, or return a non-optional.<br class=""></div><div class=""><br class=""></div><div class="">Ideally, we’d have three types of sequences, with three corresponding `sequence(first:next:)` functions:<br class=""></div><div class=""><br class=""></div><div class=""><div class=""><span class="font" style="font-family: Menlo;">func sequence<T>(first: T?, next: (T) -> T?)</span><span class="font" style="font-family: Menlo;"> — </span>returns any sequence<br class=""></div><div class=""><span class="font" style="font-family: Menlo;">func sequence<T>(first: T, next: (T) -> T?)</span><span class="font" style="font-family: Menlo;"> — </span>returns a nonempty sequence<br class=""></div></div><div class=""><span class="font" style="font-family: Menlo;">func sequence<T>(first: T, next: (T) -> T)<span class="Apple-converted-space"> </span></span><span class="font" style="font-family: Menlo;"> — </span>returns an infinite sequence<br class=""></div><div class=""><br class=""></div><div class="">Default implementations for methods on sequences would either return optionals or non-optionals depending on their emptiness/finiteness. We just have the first kind of sequence right now, so in that regard it would make sense to also give `sequence(first:next)` the corresponding signature. Later, when the language / standard library supports the other two kinds of sequences (if that ever happens), the other versions could be added.<br class=""></div><div class=""><br class=""></div><div class="">Another reason that makes me think that the version that accepts an optional `first` argument is more natural, is the fact that the function body doesn’t need to be changed at all. It supports optional seeds by design; only the signature prevents it.<br class=""></div><div class=""><br class=""></div><div class="">I know these arguments might not be very convincing, but I feel like Swift misses an opportunity if it unnecessarily constrains the `first` parameter to be non-optional. The `.lazy.flatMap({ $0 })` alternative that you pointed out does work, but it makes everything very unreadable: not just the `.lazy.flatMap({ $0 })` part, but also the body of the `next` parameter because you’re now dealing with optionals (i.e. you have to `flatMap` over the closure argument). The best solution I’ve come up with is to copy the `sequence(first:next)` implementation from the source code and change the signature. :-/<br class=""></div><div class=""><br class=""></div><div class="">`sequence(state:next:)` isn’t very appropriate for this task either, because naive usage with an optional seed has the downside of being unnecessarily eager just like a naive `sequence(first:next)` implementation (as described in a comment in the source code).<br class=""></div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On 19 Aug 2016, at 00:18, Max Moiseev <<a href="mailto:moiseev@apple.com" class="">moiseev@apple.com</a>> wrote:<br class=""></div><div class=""><br class=""></div><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;"><div class="">Hi Tim,<br class=""></div><div class=""><br class=""></div><div class="">Thanks for bringing this up.<br class=""></div><div class="">Here are my thoughts on the change you’re proposing.<br class=""></div><div class=""><br class=""></div><div class=""><span class="font" style="font-family: Menlo;"><span class="size" style="font-size: 12px;">func sequence<T>(first: T, next: (T) -> T?) -> UnfoldFirstSequence<T></span></span><br class=""></div><div class=""><br class=""></div><div class="">To me the type of the function as it is tells a clear story of what’s going to happen: take the `first`, make it a head of the resulting sequence, and then try to produce the tail by a series of applications of `next`. The only thing that controls when the sequence generation terminates is the result of `next`.<br class=""></div><div class=""><br class=""></div><div class="">If we change the type of `first` to an Optional<T>, it would make the termination condition non-trivial. After all, the only thing it would do is try to unwrap the `first`, before doing what it needs to, but we already have a `map` for that. One should be able to simply do the `first.map { sequence(first: $0, next: next) } ?? []` but that won’t work with the types very well, unfortunately.<br class=""></div><div class=""><br class=""></div><div class="">As an alternative, `let first: Int? = ...; sequence(first: first, next: next).flatMap({$0})` (or even `.lazy.flatMap({$0})`) will do the right thing without making an API more complex.<br class=""></div><div class=""><br class=""></div><div class="">I see the point of `sequence(first:next:)` to be precisely the "generate the non-empty sequence using a seed and a simple producer", for anything more than that, there is `sequence(state:next:)`.<br class=""></div><div class=""><br class=""></div><div class="">What do you think?<br class=""></div><div class=""><br class=""></div><div class="">Max<br class=""></div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Aug 14, 2016, at 4:27 PM, Tim Vermeulen via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""></div><div class=""><br class=""></div><div class=""><div class=""><div class="">sequence(first:next:) takes a non-optional first argument. Is there a reason for that? sequence(state:next:) allows empty sequences, and I don’t see why sequence(first:next:) shouldn’t. The fix would be to simply add the `?` in the function signature; no other changes are required to make it work.<br class=""></div><div class=""><br class=""></div><div class="">I considered just filing a bug report, but since this is a change of the public API...<br class=""></div><div class="">_______________________________________________<br class=""></div><div class="">swift-evolution mailing list<br class=""></div><div class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""></div><div class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></div></div></blockquote></div></div></div></blockquote></div></div></div></blockquote></div></div></div></blockquote><div class=""><br class=""></div></div></div></blockquote></div><br class="" style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">_______________________________________________</span><br style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">swift-evolution mailing list</span><br style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><a href="mailto:swift-evolution@swift.org" style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">swift-evolution@swift.org</a><br style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" style="font-family: Helvetica; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></body></html>