<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On 28. Dec 2017, at 12:34, Adrian Zubarev &lt;<a href="mailto:adrian.zubarev@devandartist.com" class="">adrian.zubarev@devandartist.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><p style="margin: 15px 0px; -webkit-margin-before: 0px;" class="">I disagree with some of your points. Do begin with, I don’t think we should disallow capturing the generic type parameter, because I think there might be a good way to prevent parameterization of nested protocols.</p><p style="margin: 15px 0px;" class="">To me this only feels like a natural consequence of nesting protocols anyways. To achieve this we have to provide an explicit associated type which will have a default type that refers to the captured outer generic type parameter. At this point we discover another issue that we cannot disambiguate generic type parameter like associated types yet and would be forced to name the associated type of the protocol differently.</p><pre style="margin: 15px 0px; font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;" class=""><code class="swift" style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">struct Generic&lt;T&gt; {
  protocol P {  
    associatedtype R = T  
    func f() -&gt; R  
  }
}
</code></pre><p style="margin: 15px 0px;" class="">As you can see I didn’t include the variable in this example, because existential are orthogonal this issue. David Hart and I still want to write a proposal to allow the<span class="Apple-converted-space">&nbsp;</span><code style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;" class="">where</code><span class="Apple-converted-space">&nbsp;</span>clause on typealiases - maybe after the forum officially launches.</p><p style="margin: 15px 0px;" class="">Above I said that there is an issue and provided an example that would solve that issue with todays syntax, but I’d rather expand this idea. Consider this syntax of a generic type and a protocol with an associated type.</p><pre style="margin: 15px 0px; font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;" class=""><code class="swift" style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">protocol Proto {
  associatedtype Element
}

Proto.Element // This is an error like this, but it's still allowed in a generic context

func function&lt;P : Proto&gt;(_: P) where P.Element == Int {}

protocol OtherProto : Proto where Element == Int {}

struct Test&lt;Element&gt; {}

extension Test where Element == Int {}

Test.Element // Can/should we allow this?
</code></pre><p style="margin: 15px 0px;" class="">If we could allow this in Swift then the above example with the nested protocol could be disambiguated nicely.</p><pre style="margin: 15px 0px; font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;" class=""><code class="swift" style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">struct Generic&lt;T&gt; {
  protocol P {  
    associatedtype T = Generic.T  
    func f() -&gt; T  
  }
}
</code></pre><p style="margin: 15px 0px;" class="">Remember that<span class="Apple-converted-space">&nbsp;</span><code style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;" class="">Generic.T</code><span class="Apple-converted-space">&nbsp;</span>is only the default for<span class="Apple-converted-space">&nbsp;</span><code style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal;" class="">P.T</code><span class="Apple-converted-space">&nbsp;</span>if you don’t set it yourself but when you conform or use that that protocol (in a generic context) you can still set it differntly.</p><p style="margin: 15px 0px;" class="">This consequence disallows protocol parameterization through nesting in a generic types, but still behaves very similar to nested generic types:</p><pre style="margin: 15px 0px; font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;" class=""><code class="swift" style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">struct Test&lt;T&gt; {
  struct NonGeneric {
    var t: T
  }

  struct Generic&lt;R&gt; {
    var t: T
    var r: R
  }
}

_ = Test&lt;String&gt;.NonGeneric(t: "😎")
_ = Test&lt;String&gt;.Generic&lt;Int&gt;(t: "🤓", r: 42)
</code></pre><p style="margin: 15px 0px;" class="">——</p><div class=""><br class=""></div></div></div></blockquote><div><br class=""></div>Yeah, that’s all well and good. I don’t think we should parameterise protocols either; it feels like Swift hasn’t been designed with those in mind, and that’s fine. You would get in to all kinds of horrible conflicts if you tried to conform to both Generic&lt;Int&gt;.P and Generic&lt;String&gt;.P, because most functions would have the same signature but possibly very different implementations. You would likely end up having to separate the conformances by using a wrapper struct — in which case, why not just make them the same protocol and have the existing duplicate-conformance rules take care of it?</div><div><br class=""></div><div>An earlier version of the proposal included something like you describe. Basically, Generic&lt;Int&gt;.P and Generic&lt;String&gt;.P would be the same protocol. They would have an associated type to represent the parameter from Generic&lt;T&gt;, and within Generic&lt;T&gt;, all references to P would be implicitly constrained so that P.T == Self.T. You would write conformances to “Generic.P” with a constraint for T, as you do today.</div><div><blockquote type="cite" class=""><div class=""><div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><p style="margin: 15px 0px;" class="">And for the existential variable inside<span class="Apple-converted-space">&nbsp;</span><code style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(234, 234, 234); margin: 0px 2px; padding: 0px 5px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;" class="">Genric</code><span class="Apple-converted-space">&nbsp;</span>it really should be something like this (when the where clause is allowed and if we can refer differently to generic type parameters as well):</p><pre style="margin: 15px 0px; font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 1px solid rgb(204, 204, 204); overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;" class=""><code class="swift" style="font-family: Menlo, Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 10pt; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(248, 248, 248); color: inherit; border: 0px; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal; -webkit-margin-before: 0px;">struct Generic&lt;T&gt; {
    …
    typealias PConstrainedByT = P where T == Self.T
    var object: PConstrainedByT
}
</code></pre><div style="margin: 15px 0px;" class=""><br class="webkit-block-placeholder"></div></div></div></blockquote><div>If we have that ability, then we can totally do capturing. Forgive me, but I understand that as pretty-much the same as generalised existentials (without local type binding).</div><div>If I can write the type of object as an existential of (generic protocol + constraints) via a typealias, then surely I must also be able to do it directly? So I could also write:</div><div><br class=""></div><div>struct Generic&lt;T&gt; {</div><div>&nbsp; &nbsp; var object: P where T == Self.T</div><div>}</div><div><br class=""></div><div>Anyway, I thought that was not on the table, and in any case I’m convinced that it should be a separate proposal. This gets to the heart of the interaction between generic types and protocols, and we all know it’s not always a smooth transition (hello AnyCollection, AnyHashable, etc...). We can cover the common cases (i.e. the Apple frameworks) without requiring capturing - especially since it’s apparently not too difficult to implement - and build from there.</div><div><br class=""></div>- Karl</div><div><br class=""><blockquote type="cite" class=""><div class=""><div class="bloop_original_html" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"><div id="bloop_customfont" style="font-family: Helvetica, Arial; font-size: 13px; margin: 0px;" class=""><br class=""></div><br class=""><div id="bloop_sign_1514458702433282816" class="bloop_sign"></div><br class=""><p class="airmail_on" style="margin: 15px 0px;">Am 27. Dezember 2017 um 19:53:36, Karl Wagner via swift-evolution (<a href="mailto:swift-evolution@swift.org" style="color: rgb(65, 131, 196); background-color: inherit; text-decoration: none;" class="">swift-evolution@swift.org</a>) schrieb:</p><blockquote type="cite" class="clean_bq" style="margin: 15px 0px;"><span style="margin-top: 0px; margin-bottom: 0px;" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class=""></div><div class="">Yeah I wrote that proposal. I eventually stripped it down to just disallow all capturing, but it was still not selected by the core team for review ¯\_(ツ)_/¯<div class=""><br class=""></div><div class="">As for capturing semantics, once you start working through use-cases, it’s becomes clear that it's going to require generalised existentials. Otherwise, how would you use a Generic&lt;T&gt;.P?</div><div class=""><br class=""></div><div class="">struct Generic&lt;T&gt; {</div><div class="">&nbsp; &nbsp; protocol P { func f() -&gt; T }</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; var object: P // uh-oh! ‘Generic protocol can only be used as a generic parameter constraint'</div><div class="">}</div><div class=""><br class=""></div><div class="">So, you would need to add a generic parameter to actually<span class="Apple-converted-space">&nbsp;</span><i class="">use</i><span class="Apple-converted-space">&nbsp;</span>P from within Generic&lt;T&gt;, which of course limits you to a single concrete type of P:</div><div class=""><br class=""></div><div class="">struct Generic&lt;T, TypeOfP&gt; where TypeOfP: Self.P { &nbsp; &nbsp; &nbsp;// Could this even work? What if P captures TypeOfP?</div><div class="">&nbsp; &nbsp; protocol P { /* … */ }</div><div class="">&nbsp; &nbsp; var object: TypeOfP</div><div class="">}</div><div class=""><br class=""></div><div class="">Which is just yucky.</div><div class=""><br class=""></div><div class="">Ideally, the type of ‘object’ should be ‘Any&lt;P where P.T == T&gt;’, to express that it can be any conforming type with the appropriate constraints. You wouldn’t need to write that all out; we could infer that capturing is equivalent to a same-type constraint (or perhaps one of these “generalised supertype constraints” that were pitched recently). But we can’t express those kinds of existentials everywhere in the type-system today, so most examples of capturing fall down pretty quickly.</div><div class=""><br class=""></div><div class="">- Karl<br class=""><div class=""><br class=""><blockquote type="cite" class="" style="margin: 15px 0px;"><div class="" style="margin-top: 0px;">On 25. Dec 2017, at 03:56, Slava Pestov via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="" style="color: rgb(65, 131, 196); background-color: inherit; text-decoration: none;">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class="" style="margin-bottom: 0px;"><div class="">There was a proposal to allow protocols to be nested inside types at one point but it didn’t move forward.<br class=""><br class="">Basically, if the outer type is a non-generic class, struct or enum, there’s no conceptual difficulty at all.<br class=""><br class="">If the outer type is a generic type or another protocol, you have a problem where the inner protocol can reference generic parameters or associated types of the outer type. This would either have to be banned, or we would need to come up with coherent semantics for it:<br class=""><br class="">struct Generic&lt;T&gt; {<br class="">&nbsp;protocol P {<br class="">&nbsp;&nbsp;&nbsp;func f() -&gt; T<br class="">&nbsp;}<br class="">}<br class=""><br class="">struct Conforms : Generic&lt;Int&gt;.P {<br class="">&nbsp;func f() -&gt; Int { … } // Like this?<br class="">}<br class=""><br class="">let c = Conforms()<br class="">c is Generic&lt;String&gt;.P // is this false? Ie, are Generic&lt;Int&gt;.P and Generic&lt;String&gt;.P different protocols?<br class=""><br class="">Slava<br class=""><br class=""><blockquote type="cite" class="" style="margin: 15px 0px;">On Dec 24, 2017, at 6:53 PM, Kelvin Ma via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="" style="color: rgb(65, 131, 196); background-color: inherit; text-decoration: none; margin-top: 0px;">swift-evolution@swift.org</a>&gt; wrote:<br class=""><br class="">is there a reason why it’s not allowed to nest a protocol declaration inside another type?<br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="" style="color: rgb(65, 131, 196); background-color: inherit; text-decoration: none;">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="" style="margin-bottom: 0px;"></blockquote><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="" style="color: rgb(65, 131, 196); background-color: inherit; text-decoration: none;">swift-evolution@swift.org</a><br 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></blockquote></div><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" style="color: rgb(65, 131, 196); background-color: inherit; text-decoration: none;" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" style="color: rgb(65, 131, 196); background-color: inherit; text-decoration: none;" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></div></span></blockquote></div><div class="bloop_markdown" style="font-family: Helvetica, Arial; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254);"></div></div></blockquote></div><br class=""></body></html>