<div dir="ltr">Hi Kevin,<div><br></div><div>The issue I was seeing was because <font face="monospace, monospace">AnySequence</font> uses the protocol extension on <font face="monospace, monospace">SequenceType</font> for its implementations of filter/suffix/prefix etc. So I don&#39;t think it&#39;s taking into account any implementations of those on the base sequence&#39;s type.</div><div><br></div><div><div>The problem basically comes down to this:</div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><font face="monospace, monospace">AnySequence([1,2,3].cycle).suffix(1)</font> uses <font face="monospace, monospace">SequenceType</font>&#39;s implementation of suffix.</div><div><font face="monospace, monospace">[1,2,3].cycle.suffix(1)</font> uses <font face="monospace, monospace">CycleSequence</font>&#39;s implementation of suffix.</div></blockquote></div><div>If you provide any custom implementations for <span style="font-family:monospace,monospace">CycleSequence</span> AnySequence will not preserve that intent. This is probably a bug.<br></div><div><br></div><div>Another side-effect of <font face="monospace, monospace">AnySequence</font> is that <span style="font-size:13px"><font face="monospace, monospace">@available(*, unavailable, message=&quot;this cannot be used on an infinite sequence&quot;) </font></span>on<span style="font-size:13px"><font face="monospace, monospace"> </font></span><span style="font-family:monospace,monospace">CycleSequence</span> will not work if you wrap it with <font face="monospace, monospace">AnySequence</font>. It would still be nice to do this, it&#39;s just not robust.</div><div><br></div><div>I&#39;ve added a bug report (<a href="https://bugs.swift.org/browse/SR-413">SR-413</a>) to add missing SequenceType methods to AnySequence so that they use the correct version. I think this should address my concerns.</div><div><br></div><div>If that bug is fixed then the only remaining problem I have is to decide is if suffix/array should enter an infinite loop or <font face="monospace, monospace">fatalError</font>. Personally I&#39;m leaning towards <font face="monospace, monospace">fatalError</font> as it&#39;s more likely to let a developer know what&#39;s wrong.</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Dec 30, 2015 at 5:44 AM, Kevin Ballard <span dir="ltr">&lt;<a href="mailto:kevin@sb.org" target="_blank">kevin@sb.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><u></u>




<div><span class=""><div>On Tue, Dec 29, 2015, at 02:27 AM, Andrew Bennett wrote:<br></div>
<blockquote type="cite"><div dir="ltr"><div>+1 looks good, I had a go at implementing it and I think it may require changes not discussed in the proposal.<br></div>
<div> </div>
<div>You&#39;ve covered the potential issues fairly well, to be a little more explicit these are the issues I&#39;ve found:<br></div>
<blockquote style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:40px;border-top-style:none;border-right-style:none;border-bottom-style:none;border-left-style:none;border-top-width:initial;border-right-width:initial;border-bottom-width:initial;border-left-width:initial;border-top-color:initial;border-right-color:initial;border-bottom-color:initial;border-left-color:initial;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px"><div> 1) LazySequenceType&#39;s property array cannot be defined without an infinite sized array.<br></div>
</blockquote></div>
</blockquote><div> </div>
</span><div>Good point, I forgot about that one. But that&#39;s really just the same thing as saying `Array(seq)`, so I don&#39;t have any problems with just saying that it&#39;s an error to access that property on an infinite sequence (in this case I&#39;d just make it fatalError()).<br></div>
<div> </div>
<div>I do wish I could mark those sorts of things with @available(*, unavailable, message=&quot;this cannot be used on an infinite sequence&quot;) to provide a compile-time error for anyone accessing it on the concrete type (generic access via the protocol wouldn&#39;t catch that of course), but I discovered that if you try and use that on a function like map(), Swift actually goes ahead and adds the default implementation to your type anyway (basically throwing away your marked-as-unavailable method). Which I suppose makes some sense, but I wish there was an alternative that worked.<br></div><span class="">
<div> </div>
<blockquote type="cite"><div dir="ltr"><blockquote style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:40px;border-top-style:none;border-right-style:none;border-bottom-style:none;border-left-style:none;border-top-width:initial;border-right-width:initial;border-bottom-width:initial;border-left-width:initial;border-top-color:initial;border-right-color:initial;border-bottom-color:initial;border-left-color:initial;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px"><div> 2) what should [1,2,3].cycle.suffix(4) return? [3,1,2,3] probably has the least surprises, but it&#39;s like asking what&#39;s the number before infinity.<br></div>
</blockquote></div>
</blockquote><div> </div>
</span><div>Nothing. You can&#39;t take a suffix on an infinite list. There is no end to it. That method should be overridden to fatalError() (or if not, it would just loop forever).</div><span class="">
<div> </div>
<blockquote type="cite"><div dir="ltr"><blockquote style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:40px;border-top-style:none;border-right-style:none;border-bottom-style:none;border-left-style:none;border-top-width:initial;border-right-width:initial;border-bottom-width:initial;border-left-width:initial;border-top-color:initial;border-right-color:initial;border-bottom-color:initial;border-left-color:initial;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px"><div> 3) dropLast should return AnySequence(self), but requires specialisation, this may have to also be a fatalError (see below).<br></div>
</blockquote></div>
</blockquote><div> </div>
</span><div>Good point. Since there is no end to the sequence, dropLast() on an infinite sequence is still an infinite sequence. Honestly, the default implementation should work fine, but it&#39;s probably a good idea to just override it to return AnySequence(self) as you suggest anyway because it&#39;s an easy win.</div><span class="">
<div> </div>
<blockquote type="cite"><div dir="ltr"><div>One issue I don&#39;t think you&#39;ve mentioned, and I don&#39;t seem to be able to resolve is this:<br></div>
<blockquote style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:40px;border-top-style:none;border-right-style:none;border-bottom-style:none;border-left-style:none;border-top-width:initial;border-right-width:initial;border-bottom-width:initial;border-left-width:initial;border-top-color:initial;border-right-color:initial;border-bottom-color:initial;border-left-color:initial;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px"><div>let mySequence = [1,2,3].cycle.dropLast(1)<br></div>
</blockquote><blockquote style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:40px;border-top-style:none;border-right-style:none;border-bottom-style:none;border-left-style:none;border-top-width:initial;border-right-width:initial;border-bottom-width:initial;border-left-width:initial;border-top-color:initial;border-right-color:initial;border-bottom-color:initial;border-left-color:initial;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px">mySequence.suffix(7)<br></blockquote><div> </div>
<div>This could have well defined behaviour (see part 2 above), however the implementation has some issues.<br></div>
</div>
</blockquote><div> </div>
</span><div>The only well-defined behavior this can have is to loop forever (or to abort with a fatalError). It&#39;s simply an error to take a suffix() of an infinite sequence.</div><span class="">
<div> </div>
<blockquote type="cite"><div dir="ltr"><div>In this case mySequence is an AnySequence&lt;Int&gt;, mySequence.suffix(7) uses AnySequence&#39;s specialisation and so tries to iterate over the entire sequence to find the suffix. AnySequence&lt;Int&gt; is type-erased so there&#39;s no way to specialise when the underlying sequence is infinite (to get a valid implementation of suffix).<br></div>
</div>
</blockquote><div> </div>
</span><div>That&#39;s fine, looping forever is a perfectly reasonable course of action when you try and take a suffix() of an infinite sequence.</div><span class="">
<div> </div>
<blockquote type="cite"><div dir="ltr"><div>Potential solutions: <br></div>
<div> * Replace erased Any* types with a more flexible alternative that doesn&#39;t remove type information (higher kinded types perhaps).<br></div>
</div>
</blockquote><div> </div>
</span><div>The whole point of the Any* types is they do remove type information.<br></div><span class="">
<div> </div>
<blockquote type="cite"><div dir="ltr"><div> * Replace SequenceType with two protocols FiniteSequenceType and InfiniteSequenceType, have type erased versions of each, duplicate all the things.<br></div>
</div>
</blockquote><div> </div>
</span><div>What&#39;s the point of this? All you can do with that is get rid of a couple of methods that would loop forever on infinite sequences, but it&#39;s a lot of work and a lot of duplication for what seems like an extremely small win.<br></div>
<div> </div>
<div>I&#39;d much rather just come up with some alternative to @available(*, unavailable) that actually leaves the method intact but provides a compile-time error if you call it. This would be strictly intended for protocol methods, as you&#39;d still need to provide an implementation (such as `fatalError(&quot;not supported&quot;)`) that would be called when the method is accessed via a generic type bound on the protocol (or via an existential protocol value, for protocols that support that).</div><span class="">
<div> </div>
<blockquote type="cite"><div dir="ltr"><div> * Add a property to SequenceType to indicate if it&#39;s definitely finite (undefined?), AnySequence uses a different backing implementation depending on this boolean.<br></div>
</div>
</blockquote><div> </div>
</span><div>And what would AnySequence do with that information? All it could really do is make sure to call fatalError() instead of looping forever when a method like suffix() is called.<span class="HOEnZb"><font color="#888888"><br></font></span></div><span class="HOEnZb"><font color="#888888">
<div> </div>
<div>-Kevin Ballard</div>
</font></span></div>

</blockquote></div><br></div>