<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body><div>On Tue, Dec 29, 2015, at 01:24 PM, Matthew Johnson wrote:<br></div>
<blockquote type="cite"><div>Hi Kevin,<br></div>
<div>&nbsp;</div>
<div>Thanks for taking time to look at the proposal.<br></div>
<div>&nbsp;</div>
<div>The technique you show here is not bad, but it has several deficiencies IMO which are addressed by the solution in the proposal.<br></div>
<div>&nbsp;</div>
<div><div>1. Forwarding should be an implementation detail, not exposed as it is with this method.<br></div>
<div>2. As such, the getter for the forwardee is visible. &nbsp;The forwardee is an implementation detail that should not be visible in most cases.<br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>I was tempted to call it `_forwardedSequence` instead, but I chose not to do that because the _prefix convention right now means "stdlib things that we don't want to expose but have to do so because of implementation details".<br></div>
<div>&nbsp;</div>
<blockquote type="cite"><div><div>3. There is no way to specify access control for the synthesized methods and if there were it would be coupled to the access control of the conformance.<br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>I'm not sure what you mean by this. Access control for these methods should work identically to access control for the original protocol. The forwarder protocol would simply be declared with the same access control.<br></div>
<div>&nbsp;</div>
<blockquote type="cite"><div><div>4. You can't forward to a type that doesn't conform to the protocol. &nbsp;This is particularly important for existential forwardees (at least until they conform to their protocol).<br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>It seems weird to me that your forwarding proposal allows you to forward to a member that doesn't conform to the protocol. I suppose it makes some sense if you only forward some methods and implement the others yourself, but I'm not convinced there's actually a good reason to support this. What circumstances are you thinking of where you'd actually find yourself forwarding to a member that doesn't conform to the protocol (that isn't an existential)? The only case that really comes to mind is when the member is of a generic type that can't conform to the protocol (e.g. Array&lt;Int&gt; doesn't conform to Equatable), but the solution there is to allow for conditional protocol conformance (which we already know is something we want in the language).<br></div>
<div>&nbsp;</div>
<div>Forwarding to existentials is a valid concern, but I'm not actually sure why Swift doesn't make existential protocol values conform to the protocol anyway. That limitation would make sense if you could create existential protocol values from protocols with Self/associated types where the existential simply omits the relevant members (because then it obviously doesn't conform to the protocol), but  Swift doesn't actually let you create existentials in that situation anyway.<br></div>
<div>&nbsp;</div>
<blockquote type="cite"><div><div>5. A type that can't conform to the protocol can't forward an implementation of the members of the protocol. &nbsp;Specifically, non-final classes cannot automatically forward a group of methods to an implementer.<br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>It sounds like you're talking here about the ability to forward members that aren't actually associated with a protocol, right? I don't see why you can't just declare a protocol in that case to represent the members that you want to be able to forward.</div>
<div>&nbsp;</div>
<blockquote type="cite"><div><div>6. This solution does not lay the foundation for a newtype feature. It would be possible to have a specialized newtype feature, but why not build it on top of a more general forwarding feature?<br></div>
</div>
</blockquote><div>&nbsp;</div>
<div>Barring a detailed newtype proposal, it's hard to see how forwarding would actually interact with it. Are you thinking that a newtype would have some member that provides the underlying value (e.g. a `var rawValue`)? Given such a member, a generalized forwarding mechanism would then interact with it. But if e.g. newtype works by letting you cast (with `as`) to the underlying type, then your generalized forwarding mechanism can't actually work unless it has two different modes (one of which uses a member and the other uses a cast), which means you're specializing for newtype anyway.<br></div>
<div>&nbsp;</div>
<div>Besides, when using a newtype mechanism like that, since the newtype has the same in-memory representation as the original type, you don't actually want to generate new methods at all for forwarding, instead you just want to re-use the exact same methods as the original type (otherwise you're just bloating your code with a bunch of stubs that do nothing more than bitcast the value and call the original method).<br></div>
<div>&nbsp;</div>
<div>-Kevin Ballard</div>
<div>&nbsp;</div>
<blockquote type="cite"><div>You may be right that many protocols are not amenable to forwarding. &nbsp;The motivation for this proposal is that it enables delegation-based designs to be implemented succinctly. &nbsp;In that use case the protocols will be designed alongside concrete implementations and types that forward to them. &nbsp;A secondary motivation for this proposal is to lay a foundation for a newtype feature. &nbsp;In that case the protocols to be forwarded would be specifically designed to represent the portion of the interface of the wrapped type which should be visible to users of the newtype.<br></div>
<div>&nbsp;</div>
<div>I hope these points might be enough to convince you that it is worth a closer look.<br></div>
<div>&nbsp;</div>
<div>Matthew<br></div>
<div><div>&nbsp;</div>
<div><blockquote type="cite"><div>On Dec 29, 2015, at 2:06 PM, Kevin Ballard via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br></div>
<div>&nbsp;</div>
<div><div><div>I briefly skimmed your proposal, so I apologize if you already addressed this, but it occurs to me that we could support automatic protocol forwarding today on a per-protocol basis simply by declaring a separate protocol that provides default implementations doing the forwarding. Handling of Self return types can then be done by adding a required initializer (or just not implementing that method, so the concrete type is forced to deal with it even though everything else is forwarded).<br></div>
<div>&nbsp;</div>
<div>For example, if I want to automatically forward SequenceType to a member, I can do something like<br></div>
<div>&nbsp;</div>
<div><div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">protocol</span> SequenceTypeForwarder : <span class="colour" style="color:rgb(112, 61, 170)">SequenceType</span> {<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">typealias</span> ForwardedSequenceType : SequenceType<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">var</span> forwardedSequence : <span class="colour" style="color:rgb(112, 61, 170)">ForwardedSequenceType</span> { <span class="colour" style="color:rgb(187, 44, 162)">get</span> }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">}<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112, 61, 170);"><span class="colour" style="color:rgb(187, 44, 162)">extension</span><span style=""></span>SequenceTypeForwarder<span style=""> {</span><br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112, 61, 170);"><span style=""></span><span class="colour" style="color:rgb(187, 44, 162)">func</span><span style=""> generate() -&gt; </span>ForwardedSequenceType<span style="">.</span>Generator<span style=""> {</span><br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> forwardedSequence.generate()<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">func</span> underestimateCount() -&gt; <span class="colour" style="color:rgb(112, 61, 170)">Int</span> {<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> forwardedSequence.underestimateCount()<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">func</span> map&lt;T&gt;(<span class="colour" style="color:rgb(187, 44, 162)">@noescape</span> transform: (ForwardedSequenceType.Generator.Element) <span class="colour" style="color:rgb(187, 44, 162)">throws</span> -&gt; T) <span class="colour" style="color:rgb(187, 44, 162)">rethrows</span> -&gt; [<span class="colour" style="color:rgb(112, 61, 170)">T</span>] {<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> <span class="colour" style="color:rgb(187, 44, 162)">try</span> forwardedSequence.map(transform)<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">func</span> filter(<span class="colour" style="color:rgb(187, 44, 162)">@noescape</span> includeElement: (ForwardedSequenceType.Generator.Element) <span class="colour" style="color:rgb(187, 44, 162)">throws</span> -&gt; Bool) <span class="colour" style="color:rgb(187, 44, 162)">rethrows</span> -&gt; [<span class="colour" style="color:rgb(112, 61, 170)">ForwardedSequenceType</span>.<span class="colour" style="color:rgb(112, 61, 170)">Generator</span>.<span class="colour" style="color:rgb(112, 61, 170)">Element</span>] {<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> <span class="colour" style="color:rgb(187, 44, 162)">try</span> forwardedSequence.filter(includeElement)<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">func</span> forEach(<span class="colour" style="color:rgb(187, 44, 162)">@noescape</span> body: (ForwardedSequenceType.Generator.Element) <span class="colour" style="color:rgb(187, 44, 162)">throws</span> -&gt; Void) <span class="colour" style="color:rgb(187, 44, 162)">rethrows</span> {<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> <span class="colour" style="color:rgb(187, 44, 162)">try</span> forwardedSequence.forEach(body)<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112, 61, 170);"><span style=""></span><span class="colour" style="color:rgb(187, 44, 162)">func</span><span style=""> dropFirst(n: </span>Int<span style="">) -&gt; </span>ForwardedSequenceType<span style="">.</span>SubSequence<span style=""> {</span><br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> forwardedSequence.dropFirst(n)<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112, 61, 170);"><span style=""></span><span class="colour" style="color:rgb(187, 44, 162)">func</span><span style=""> dropLast(n: </span>Int<span style="">) -&gt; </span>ForwardedSequenceType<span style="">.</span>SubSequence<span style=""> {</span><br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> forwardedSequence.dropLast(n)<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112, 61, 170);"><span style=""></span><span class="colour" style="color:rgb(187, 44, 162)">func</span><span style=""> prefix(maxLength: </span>Int<span style="">) -&gt; </span>ForwardedSequenceType<span style="">.</span>SubSequence<span style=""> {</span><br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> forwardedSequence.prefix(maxLength)<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112, 61, 170);"><span style=""></span><span class="colour" style="color:rgb(187, 44, 162)">func</span><span style=""> suffix(maxLength: </span>Int<span style="">) -&gt; </span>ForwardedSequenceType<span style="">.</span>SubSequence<span style=""> {</span><br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> forwardedSequence.suffix(maxLength)<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">func</span> split(maxSplit: Int, allowEmptySlices: Bool, <span class="colour" style="color:rgb(187, 44, 162)">@noescape</span> isSeparator: (ForwardedSequenceType.Generator.Element) <span class="colour" style="color:rgb(187, 44, 162)">throws</span> -&gt; Bool) <span class="colour" style="color:rgb(187, 44, 162)">rethrows</span> -&gt; [<span class="colour" style="color:rgb(112, 61, 170)">ForwardedSequenceType</span>.<span class="colour" style="color:rgb(112, 61, 170)">SubSequence</span>] {<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">return</span> <span class="colour" style="color:rgb(187, 44, 162)">try</span> forwardedSequence.split(maxSplit, allowEmptySlices: allowEmptySlices, isSeparator: isSeparator)<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">&nbsp; &nbsp; }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">}<br></div>
</div>
<div>&nbsp;</div>
<div>With this protocol declared, I can then say something like<br></div>
<div>&nbsp;</div>
<div><div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">struct</span> Foo {<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">var</span> ary: [<span class="colour" style="color:rgb(112, 61, 170)">Int</span>]<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">}<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px;">&nbsp;</div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112, 61, 170);"><span class="colour" style="color:rgb(187, 44, 162)">extension</span><span style=""></span>Foo<span style=""> : </span>SequenceTypeForwarder<span style=""> {</span><br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;"><span class="colour" style="color:rgb(187, 44, 162)">var</span> forwardedSequence: [<span class="colour" style="color:rgb(112, 61, 170)">Int</span>] { <span class="colour" style="color:rgb(187, 44, 162)">return</span> ary }<br></div>
<div style="margin-top:0px;margin-bottom:0px;font-size:11px;line-height:normal;font-family:Menlo;">}<br></div>
</div>
<div>&nbsp;</div>
<div>and my struct Foo now automatically implements SequenceType by forwarding to its variable `ary`.<br></div>
<div>&nbsp;</div>
<div>The downside to this is it needs to be manually declared for each protocol. But I wager that most protocols actually aren't really amenable to forwarding anyway.<br></div>
<div>&nbsp;</div>
<div>-Kevin Ballard<br></div>
<div><img style="height:1px !important;width:1px !important;border-top-width:0px !important;border-right-width:0px !important;border-bottom-width:0px !important;border-left-width:0px !important;margin-top:0px !important;margin-bottom:0px !important;margin-right:0px !important;margin-left:0px !important;padding-top:0px !important;padding-bottom:0px !important;padding-right:0px !important;padding-left:0px !important;" border="0" height="1" width="1" alt="" src="https://www.fastmailusercontent.com/proxy/19d6d3ba9d65bf59fd6cecf5353444fa4729ec326d468f378628d572dee23bba/8647470737a3f2f25723030323431303e23647e23756e64676279646e2e65647f27766f2f60756e6f35707e6d356c464d427b4444583962487a5d2236426e6b6d22324a51767353686e4e4d2236467958546365614034573658777b6146613a795171403564437368426849335449775a6a7747564c49686a5e637f6a797974377d475345393c453b6861435950703f695931364544654d22364d6544536a4966423f4a77393630307149415276354f467d62474b4d46636d223649353d696d4a65603c416e62435c6835785c4976466d4d6036645431645d2232473478475a44403d46476f415d2236456d60536f64653b633d2236457e476a5a556450746832314e4074537851705277473a7d444332373158335341666f627c6d486a7244557644587d22324941494d23344/open"><br></div>
</div>
<div>_______________________________________________<br></div>
<div>swift-evolution mailing list<br></div>
<div><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br></div>
<div>https://lists.swift.org/mailman/listinfo/swift-evolution<br></div>
</div>
</blockquote></div>
</div>
</blockquote><div>&nbsp;</div>
</body>
</html>