<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="">Here’s an attempt to implement this with existing language features:<div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">protocol HasElementType {</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="">&nbsp; func getElement() -&gt; Any.Type?</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="">}</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" class="">extension HasElementType {</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="">&nbsp; func getElement() -&gt; Any.Type? {</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="">&nbsp; &nbsp; return nil</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="">&nbsp; }</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="">}</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" class="">extension Array : HasElementType {</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="">&nbsp; func getElement() -&gt; Any.Type? {</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="">&nbsp; &nbsp; return Element.self</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="">&nbsp; }</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="">}</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" class="">func isArrayWithElementType&lt;T&gt;(a: Any, _ m: T.Type) -&gt; Bool {</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="">&nbsp; guard let aa = a as? HasElementType else { return false }</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="">&nbsp; guard let elt = aa.getElement() else { return false }</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="">&nbsp; return elt is T.Type</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="">}</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" class="">protocol P {}</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="">struct X : P {}</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" class="">print(isArrayWithElementType([1,2,3,4,5], Int.self))</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="">print(isArrayWithElementType([1,2,3,4,5], Float.self))</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="">print(isArrayWithElementType(["a", "b"], String.self))</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="">print(isArrayWithElementType([X()], X.self))</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="">print(isArrayWithElementType([X()], P.self))</span></div></blockquote><br class=""></div><div class="">However, the limitation here is that when we do ‘elt is T.Type’, if elt is a metatype conforming to a protocol P, and T is P, the ‘is’ check just checks for metatype identity and not conformance.</div><div class=""><br class=""></div><div class="">So if a generic parameter T is bound to a concrete type C, then T.Type means C.Type. However, if C is a protocol type, then T.Type is really C.Protocol, not C.Type.</div><div class=""><br class=""></div><div class="">Here’s a silly idea:</div><div class=""><br class=""></div><div class="">- Switch P.Type and P.Protocol syntax where P is a protocol type, so that P.Type is the type of P.self, and P.Protocol is the existential metatype. This makes ‘P.Type’ consistent with ’T.Type’ where T is bound to a protocol type. It also makes ‘P.Protocol’ kind of like a protocol — types that conform to P have metatypes that conform to P.Protocol.</div><div class=""><br class=""></div><div class="">- Add a ‘: protocol’ generic constraint, asserting that the type parameter is some protocol existential type:</div><div class=""><br class=""></div><div class="">&nbsp; func isArrayWithElementType&lt;T : protocol&gt;(…)</div><div class=""><br class=""></div><div class="">- For a generic type parameter T with an existential constraint, you would be able to write T.Protocol to refer to the existential metatype. T.self would not be an instance of T.Protocol, but the elements of your array that *conform* to T would be instances of T.Protocol.</div><div class=""><br class=""></div><div class="">Maybe also we want to allow casts with a metatype expression, rather than a type identifier, on the RHS.</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">Or perhaps, if we need angle brackets to be somewhere, something like this:</div><div class=""><div class=""><br class="">if let arr = someObject as? &lt;T: Foo&gt; Array&lt;T&gt; {<br class=""></div></div></blockquote><div><br class=""></div>Yeah, it’s going to have to be this, since &lt;T : Foo&gt; is shorthand for &lt;T where T : Foo&gt;, and in general the &lt;&gt; of a bound generic type reference are different from &lt;&gt; in a generic signature — the latter introduces new type variables for instance.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>…<br class="">}<br class=""><br class="">Is this a feasible thing to ask for?<br class=""></div></div></blockquote><div><br class=""></div>I think so, but we have to careful with the design. This ties in with some of the discussions on generalizing existential types, also.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><br class="">(Apologies if there’s already a way to do this; I was looking for one without success.)<br class=""><br class="">Charles<br class=""><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></div></blockquote></div><br class=""></div></body></html>