<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body><div>On Tue, Dec 29, 2015, at 10:12 PM, Andrew Bennett wrote:<br></div>
<blockquote type="cite"><div dir="ltr"><div>Hi Kevin,<br></div>
<div>&nbsp;</div>
<div>The issue I was seeing was because <span class="font" style="font-family:monospace, ' monospace'">AnySequence</span> uses the protocol extension on <span class="font" style="font-family:monospace, ' monospace'">SequenceType</span> for its implementations of filter/suffix/prefix etc. So I don't think it's taking into account any implementations of those on the base sequence's type.<br></div>
<div>&nbsp;</div>
<div><div>The problem basically comes down to 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;border-image-source:initial;border-image-slice:initial;border-image-width:initial;border-image-outset:initial;border-image-repeat:initial;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;"><div><span class="font" style="font-family:monospace, ' monospace'">AnySequence([1,2,3].cycle).suffix(1)</span>&nbsp;uses&nbsp;<span class="font" style="font-family:monospace, ' monospace'">SequenceType</span>'s implementation of suffix.<br></div>
<div><span class="font" style="font-family:monospace, ' monospace'">[1,2,3].cycle.suffix(1)</span>&nbsp;uses&nbsp;<span class="font" style="font-family:monospace, ' monospace'">CycleSequence</span>'s implementation of suffix.<br></div>
</blockquote></div>
<div>If you provide any custom implementations for&nbsp;<span class="font" style="font-family:monospace, monospace">CycleSequence</span>&nbsp;AnySequence will not preserve that intent. This is probably a bug.<br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>The only way to actually fix this is to have AnySequence contain a closure for each method defined in SequenceType that calls the underlying implementation (and wraps the result in AnySequence as necessary). This is rather heavy-weight, which is probably why it doesn't do that.<br></div>
<div>&nbsp;</div>
<div>Really, I don't think it's particularly surprising that wrapping a sequence in AnySequence causes the sequence's own implementations of the optional methods to not be called. It would be great if there was a simple way to fix this, but it's not worth the cost of reifying all the runtime type information necessary.</div>
<div>&nbsp;</div>
<blockquote type="cite"><div dir="ltr"><div>Another side-effect of <span class="font" style="font-family:monospace, ' monospace'">AnySequence</span> is that&nbsp;<span class="size" style="font-size:13px"><span class="font" style="font-family:monospace, ' monospace'">@available(*, unavailable, message="this cannot be used on an infinite sequence")&nbsp;</span></span>on<span class="font" style="font-family:monospace, monospace">CycleSequence</span>&nbsp;will not work if you wrap it with <span class="font" style="font-family:monospace, ' monospace'">AnySequence</span>. It would still be nice to do this, it's just not robust.<br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>Since that's a compile-time check, it is quite impossible to ever support that on a sequence that's wrapped in AnySequence.<br></div>
<div>&nbsp;</div>
<div>-Kevin Ballard</div>
<div>&nbsp;</div>
<blockquote type="cite"><div dir="ltr"><div>I'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.<br></div>
<div>&nbsp;</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 <span class="font" style="font-family:monospace, ' monospace'">fatalError</span>. Personally I'm leaning towards <span class="font" style="font-family:monospace, ' monospace'">fatalError</span> as it's more likely to let a developer know what's wrong.<br></div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div><div>On Wed, Dec 30, 2015 at 5:44 AM, Kevin Ballard <span dir="ltr">&lt;<a href="mailto:kevin@sb.org">kevin@sb.org</a>&gt;</span> wrote:<br></div>
<blockquote style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204, 204, 204);border-left-style:solid;padding-left:1ex;"><div><u></u><br></div>
<div><div>&nbsp;</div>
<div><span>On Tue, Dec 29, 2015, at 02:27 AM, Andrew Bennett wrote:</span><br></div>
<blockquote type="cite"><div dir="ltr"><div><span>+1 looks good, I had a go at implementing it and I think it may require changes not discussed in the proposal.</span><br></div>
<div>&nbsp;</div>
<div><span>You've covered the potential issues fairly well, to be a little more explicit these are the issues I've found:</span><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><span>&nbsp;1) LazySequenceType's property array cannot be defined without an infinite sized array.</span><br></div>
</blockquote></div>
</blockquote><div>&nbsp;</div>
<div>&nbsp;</div>
<div>Good point, I forgot about that one. But that's really just the same thing as saying `Array(seq)`, so I don't have any problems with just saying that it's an error to access that property on an infinite sequence (in this case I'd just make it fatalError()).<br></div>
<div>&nbsp;</div>
<div>I do wish I could mark those sorts of things with @available(*, unavailable, message="this cannot be used on an infinite sequence") to provide a compile-time error for anyone accessing it on the concrete type (generic access via the protocol wouldn'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>
<div>&nbsp;</div>
<div>&nbsp;</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><span>&nbsp;2) what should [1,2,3].cycle.suffix(4) return? [3,1,2,3] probably has the least surprises, but it's like asking what's the number before infinity.</span><br></div>
</blockquote></div>
</blockquote><div>&nbsp;</div>
<div>&nbsp;</div>
<div>Nothing. You can'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).<br></div>
<div>&nbsp;</div>
<div>&nbsp;</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><span>&nbsp;3) dropLast should return AnySequence(self), but requires specialisation, this may have to also be a fatalError (see below).</span><br></div>
</blockquote></div>
</blockquote><div>&nbsp;</div>
<div>&nbsp;</div>
<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's probably a good idea to just override it to return AnySequence(self) as you suggest anyway because it's an easy win.<br></div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<blockquote type="cite"><div dir="ltr"><div><span>One issue I don't think you've mentioned, and I don't seem to be able to resolve is this:</span><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><span>let mySequence = [1,2,3].cycle.dropLast(1)</span><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;"><span>mySequence.suffix(7)</span><br></blockquote><div>&nbsp;</div>
<div><span>This could have well defined behaviour (see part 2 above), however the implementation has some issues.</span><br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>&nbsp;</div>
<div>The only well-defined behavior this can have is to loop forever (or to abort with a fatalError). It's simply an error to take a suffix() of an infinite sequence.<br></div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<blockquote type="cite"><div dir="ltr"><div><span>In this case&nbsp;mySequence&nbsp;is an AnySequence&lt;Int&gt;,&nbsp;mySequence.suffix(7) uses AnySequence's specialisation and so tries to iterate over the entire sequence to find the suffix. AnySequence&lt;Int&gt; is type-erased so there's no way to specialise when the underlying sequence is infinite (to get a valid implementation of suffix).</span><br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>&nbsp;</div>
<div>That's fine, looping forever is a perfectly reasonable course of action when you try and take a suffix() of an infinite sequence.<br></div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<blockquote type="cite"><div dir="ltr"><div><span>Potential solutions:&nbsp;</span><br></div>
<div><span>&nbsp;* Replace erased Any* types with a more flexible alternative that doesn't remove type information (higher kinded types perhaps).</span><br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>&nbsp;</div>
<div>The whole point of the Any* types is they do remove type information.<br></div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<blockquote type="cite"><div dir="ltr"><div><span>&nbsp;* Replace SequenceType with two protocols FiniteSequenceType and InfiniteSequenceType, have type erased versions of each, duplicate all the things.</span><br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>&nbsp;</div>
<div>What'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's a lot of work and a lot of duplication for what seems like an extremely small win.<br></div>
<div>&nbsp;</div>
<div>I'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'd still need to provide an implementation (such as `fatalError("not supported")`) 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).<br></div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<blockquote type="cite"><div dir="ltr"><div><span>&nbsp;* Add a property to SequenceType to indicate if it's definitely finite (undefined?), AnySequence uses a different backing implementation depending on this boolean.</span><br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>&nbsp;</div>
<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><span class="colour" style="color:rgb(136, 136, 136)"></span></span><br></div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div><span><span class="colour" style="color:rgb(136, 136, 136)">-Kevin Ballard</span></span><br></div>
<div>&nbsp;</div>
</div>
</blockquote></div>
</div>
</blockquote><div>&nbsp;</div>
</body>
</html>