<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="">Hello all,<div class=""><br class=""></div><div class="">If you’ve been (attempting) protocol-oriented development in your own projects, I’m sure you’ve come across a particular build error at one point:</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class="">Protocol ‘MyProtocol' can only be used as a generic constraint because it has Self or associated type requirements<br class=""></blockquote><div class=""><br class=""></div><div class="">To be frank, this restriction in the current Swift model sucks, a lot. In *many* cases, this prevents me from using protocols, and instead I have to fall back to using concrete types.</div></div><div class=""><br class=""></div><div class="">Here are a couple examples of using protocols with collections that should work fine, but simply don’t:</div><div class=""><br class=""></div><div class=""><b class="">A Set of Types Conforming to Protocol</b></div><div class=""><b class=""><br class=""></b></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> MyProtocol: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Hashable&nbsp;</span>{}</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> set = </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Set</span><span style="font-variant-ligatures: no-common-ligatures" class="">&lt;</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">&gt;()&nbsp;</span><span style="color: rgb(0, 132, 0);" class="">// ERROR: Protocol ‘MyProtocol' can only be used as a generic constraint because it has Self or associated type requirements</span></div></div><div class=""><b class=""><br class=""></b></div><div class="">When declaring a Set, the generic type of the Set’s contents must conform to Hashable. Following this, it would appear that you should be able to declare a Set containing types conforming to a given protocol which in turn conforms to Hashable. Nope! This also means you can’t have a Set&lt;Hashable&gt; (so no type-erased Sets for you!). One potential workaround is to use a box type, but if exposing the set to a user, this is essentially a leaky abstraction.</div><div class=""><br class=""></div><div class=""><b class="">Finding a Protocol Type Instance in an Array</b></div><div class=""><b class=""><br class=""></b></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">&nbsp;{}</span></div></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">struct</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> MyStruct: </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> {}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">var</span><span style="font-variant-ligatures: no-common-ligatures" class=""> array = [</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">]()</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(79, 129, 135);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">array</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #3d1d81" class="">append</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">(</span><span style="font-variant-ligatures: no-common-ligatures" class="">MyStruct</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">())</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> index = </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">array</span><span style="font-variant-ligatures: no-common-ligatures" class="">.index(of: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyStruct</span><span style="font-variant-ligatures: no-common-ligatures" class="">())</span><span style="font-variant-ligatures: no-common-ligatures;" class="">&nbsp;</span><span style="color: rgb(0, 132, 0);" class="">// ERROR: Cannot invoke 'index' with an argument list of type '(of: MyStruct)'</span></div></div><div class=""><b class=""><br class=""></b></div><div class="">So, we can’t use Set as a collection for our protocol types, let’s use Array instead! Not so fast: because MyProtocol doesn’t conform to Equatable, we can’t use the Array.index(of:) function to find it. Easy fix though, just make MyProtocol conform to Equatable, right?</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> MyProtocol: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Equatable</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">struct</span><span style="font-variant-ligatures: no-common-ligatures" class=""> MyStruct: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">var</span><span style="font-variant-ligatures: no-common-ligatures" class=""> array = [</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">]()&nbsp;</span><span style="color: rgb(0, 132, 0);" class="">// ERROR: Protocol ‘MyProtocol' can only be used as a generic constraint because it has Self or associated type requirements</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(79, 129, 135);" class=""><br class=""></div></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class="">Nope! Now that it conforms to Equatable, it can no longer be used in Array’s type declaration. However, there is a (somewhat) workaround for this problem:</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class=""><br class=""></span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> MyProtocol {}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> ==(lhs: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">, rhs: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">) -&gt; </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Bool</span><span style="font-variant-ligatures: no-common-ligatures" class=""> { </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">true</span><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">struct</span><span style="font-variant-ligatures: no-common-ligatures" class=""> MyStruct: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">var</span><span style="font-variant-ligatures: no-common-ligatures" class=""> array = [</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">]()</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(79, 129, 135);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">array</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #3d1d81" class="">append</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">(</span><span style="font-variant-ligatures: no-common-ligatures" class="">MyStruct</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">())</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> index = </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">array</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #3d1d81" class="">index</span><span style="font-variant-ligatures: no-common-ligatures" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">where</span><span style="font-variant-ligatures: no-common-ligatures" class="">: { $0 </span><span style="font-variant-ligatures: no-common-ligatures; color: #31595d" class="">==</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">MyStruct</span><span style="font-variant-ligatures: no-common-ligatures" class="">() })</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class=""><span style="font-family: Helvetica; font-size: 12px;" class="">Basically, we can define the == function for MyProtocol, and then instead of using&nbsp;</span></span>Array.index(of:), we use&nbsp;Array.index(where:) to manually compare each item to see if it matches, aka what Array.index(of:) would do for us normally if we simply could declare MyProtocol as conforming to equatable.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class=""><b class="">TL;DR</b></div><div style="margin: 0px; line-height: normal;" class="">Swift really pushes the idea of protocol-oriented programming, and for the most part this works well. However, due to some underlying restrictions in the current Swift model, you can’t use protocols in all the same places you can use concrete types, which sucks. This is especially confusing for beginners who are trying to use protocols, but get frustrated when it doesn’t work where they want it to (and don’t understand why), so they fall back to using concrete types (usually implemented with class inheritance). For this reason, I think these restrictions need to be fixed ASAP, or else the Swift language is essentially pushing people away from protocol-oriented programming.</div><div style="margin: 0px; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class="">Riley Testut</div></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div></body></html>