<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=""><div class="">Jordan,</div><div class=""><br class=""></div><div class="">Your comments brought up a few more closely related ideas that have been bubbling under.</div><div class=""><br class=""></div><div class="">To everyone,</div><div class=""><br class=""></div><div class="">Sorry for going beyond topic here. The discussion of the further proposals below should be taken into their own threads if there's interest. I'm just trying to motivate what else moving out the `<font face="Menlo" style="font-size: 11px;" class="">where</font>` clause would make possible.</div><div class=""><br class=""></div><div class=""><font size="4" class=""><b class="">1. My counter-proposal against making generic parameters public</b></font></div><br class=""><div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Another factor here is that we've been planning for a while for generic parameters to types to be exposed as implicit member typealiases, since they already conflict with the namespace for member typealiases. Therefore it's important to name generic parameters to types well, but less important to do so for generic parameters for functions. (They're also much less likely to be ad hoc for types; there has to be<span class="Apple-converted-space"> </span><i class="">something</i> that describes the relation between the Self type and the parameter, while the function might not have anything more interesting than "operand".)</div><div style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></div></blockquote><div><br class=""></div><div>I disagree with that. I think it's more natural to restrict generic type parameters to the immediate local scope of the <font face="Menlo" class=""><span style="font-size: 11px;" class="">class</span></font>/<span style="font-family: Menlo; font-size: 11px;" class="">struct</span>/<span style="font-family: Menlo; font-size: 11px;" class="">enum</span> definition or extension, and simply allow making the type public with `<font face="Menlo" style="font-size: 11px;" class="">typealias</font>`. For example, this would make `<font face="Menlo" style="font-size: 11px;" class="">Element</font>` a public member of `<font face="Menlo" style="font-size: 11px;" class="">Array</font>`:</div><div><br class=""></div><div><font face="Menlo" style="font-size: 11px;" class=""> <b class="">public enum Result<T, Error></b> {</font></div><div><font face="Menlo" style="font-size: 11px;" class=""> public <b class="">typealias Value = T </b></font><span style="color: rgb(79, 122, 40); font-family: Menlo; font-size: 11px;" class="">//</span><span style="color: rgb(79, 122, 40); font-family: Menlo; font-size: 11px;" class=""> This makes `Value` public for extensions and everyone</span></div><div><font face="Menlo" style="font-size: 11px;" class=""> }</font></div><div><br class=""></div><div>I would even allow <i class="">publishing</i> the otherwise local name by repeating it in `<font face="Menlo" style="font-size: 11px;" class="">typealias</font>` like this:</div><div><br class=""></div><div><div><font face="Menlo" style="font-size: 11px;" class=""> public struct Array<Element> { </font><span style="color: rgb(79, 122, 40); font-family: Menlo; font-size: 11px;" class="">//</span><span style="color: rgb(79, 122, 40); font-family: Menlo; font-size: 11px;" class=""> This `Element` is only available in (the missing) where clause and the scope below.</span></div><div><font face="Menlo" style="font-size: 11px;" class=""> public <b class="">typealias Element = Element</b> <font color="#4f7a28" class="">// This line makes `Element` available everywhere, see below.</font></font></div><div><font face="Menlo" style="font-size: 11px;" class=""> }</font></div><div><font face="Menlo" style="font-size: 11px;" class=""><br class=""></font></div><div><span style="font-size: 11px; font-family: Menlo;" class=""> extension </span><b style="font-size: 11px; font-family: Menlo;" class="">Array<T></b><span style="font-size: 11px; font-family: Menlo;" class=""> { </span><font color="#4f7a28" style="font-size: 11px; font-family: Menlo;" class="">// <- Regardless of the pattern (`T`) used here,</font></div><div><font face="Menlo" style="font-size: 11px;" class=""> var mid: <b class="">Element?</b> { <font color="#4f7a28" class="">// the type `Element = T` is available here</font></font></div><div><font face="Menlo" style="font-size: 11px;" class=""> return ... </font><span style="color: rgb(79, 122, 40); font-family: Menlo; font-size: 11px;" class="">// because it was made public elsewhere.</span></div><div><font face="Menlo" style="font-size: 11px;" class=""> }</font></div><div><font face="Menlo" style="font-size: 11px;" class=""> }</font></div><div><font face="Menlo" style="font-size: 11px;" class=""> </font><span style="font-size: 11px; font-family: Menlo;" class="">extension </span><b style="font-size: 11px; font-family: Menlo;" class="">Array<Optional<T>></b><span style="font-size: 11px; font-family: Menlo;" class=""> { <font color="#4f7a28" class="">// <- An example of pattern matching (see further below).</font></span></div><div><span style="font-family: Menlo; font-size: 11px;" class=""> </span><span style="color: rgb(79, 122, 40); font-family: Menlo; font-size: 11px;" class="">// </span><span style="color: rgb(79, 122, 40); font-family: Menlo; font-size: 11px;" class="">Ditto, `Element = T?`</span></div><div><span style="font-family: Menlo; font-size: 11px;" class=""><font color="#4f7a28" class=""> </font>}</span></div><div><font face="Menlo" style="font-size: 11px;" class=""><br class=""></font></div><div class=""><font style="font-size: 12px;" class=""><div style="font-size: 13px;"><font face="Menlo" style="font-size: 11px;" class=""> typealias Ints = [Int]</font></div><div style="font-size: 13px;"><font face="Menlo" style="font-size: 11px;" class=""> let x: Ints<b class="">.Element</b> = ... <font color="#4f7a28" class="">// Int</font></font></div><div style="font-size: 13px;"><font face="Menlo" style="font-size: 11px;" class=""><br class=""></font></div></font></div><div class=""><font class="">Next, I propose how to extend this syntax with pattern matching. The above thinking is a natural progression from the use of pattern matching for introducing generic type parameters in type `<font face="Menlo" style="font-size: 11px;" class="">extension</font>`s.</font></div><div class=""><font class=""><br class=""></font></div><div class=""><font class=""><br class=""></font></div><div class=""><font size="4" class=""><b class="">2. Proposal to enable pattern matching of generic types in generic parameters</b></font></div><div class=""><font face="Menlo" style="font-size: 11px;" class=""><br class=""></font></div></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">This is also a minor point<span class="Apple-converted-space"> </span><i class="">against</i> declaring generic parameters for extensions, since they would have to match up. We also do need a syntax some day to represent<span class="Apple-converted-space"> </span><i class="">new</i> parameters:</div><div style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><blockquote class="" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">// For expository purposes only:</div></blockquote><blockquote class="" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="">extension <T> Array where Element == Optional<T></div></blockquote><div style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">But that deserves its own proposal. I just don't want us to paint ourselves into a corner.</div></div></blockquote><br class=""></div><div>I agree that we need that feature. But instead of your proposed syntax, I'd take influence from the already existing pattern matching that we have at value level, such that:</div><div><br class=""></div><div>1. <b class="">any <i class="">generic</i> type expressions</b> within the angle brackets `<span style="font-family: Menlo; font-size: 11px;" class=""><...></span>` are taken <b class="">as patterns to match against </b> (e.g. `<span style="font-family: Menlo; font-size: 11px;" class="">Array<</span><span style="font-family: Menlo; font-size: 11px;" class="">Element</span><span style="font-family: Menlo; font-size: 11px;" class="">></span>`, `<span style="font-family: Menlo; font-size: 11px;" class="">Optional<Foo></span>`, `<span style="font-family: Menlo; font-size: 11px;" class="">Dictionary<S, S></span>`), and</div><div>2. <span style="font-weight: bold;" class="">all non-generic type identifiers</span><b class=""> </b>in those expressions are taken <b class="">as generic parameters</b> and not concrete types (`<span style="font-family: Menlo; font-size: 11px;" class="">Element</span>`, `<span style="font-family: Menlo; font-size: 11px;" class="">Foo</span>`, or `<span style="font-size: 11px;" class=""><font face="Menlo" class="">S</font></span>`, respectively).</div><div><br class=""></div><div>Your example would translate into the first of these two:</div><div><br class=""></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> extension <b class="">Array<Optional<T>></b> { <font color="#4f7a28" class="">// extending [T?] doesn't even need any `where` clause</font></span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> func unwrapAll() -> [T] { ... }</span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> }</span></font></div><div><br class=""></div><div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> extension <b class="">Dictionary<K, Dictionary<K, V>></b> { <font color="#4f7a28" class="">// This pattern match requires the same `K` twice.</font></span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> subscript(x: K, y: K) -> V { ... }</span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> }</span></font></div><div><br class=""></div><div>The generic parameters would shadow any existing names in the outer scope, i.e. `<font face="Menlo" style="font-size: 11px;" class="">extension Array<String></font>` would mean the same as `<font face="Menlo" style="font-size: 11px;" class="">extension Array<Element></font>`. But it would be a good idea to add a warning (or linter error) at least when stdlib types such as `<font face="Menlo" style="font-size: 11px;" class="">Swift.String</font>` are shadowed like that. I think the benefits from pattern matching outweigh the possible confusion, especially since you can't use any members of `<font face="Menlo" style="font-size: 11px;" class="">String</font>` if you mistakenly wrote `<font face="Menlo" style="font-size: 11px;" class="">extension Array<String> { ... }</font>` instead of `<font face="Menlo" style="font-size: 11px;" class="">extension Array<T> where T == String</font>`.</div><div><br class=""></div></div><div><div>With this syntax, we could also allow extending <span style="font-family: Menlo; font-size: 11px;" class="">Array</span>, <span style="font-family: Menlo; font-size: 11px;" class="">Dictionary</span>, and <span style="font-family: Menlo; font-size: 11px;" class="">Optional</span> in their more natural notation:</div><div class=""><br class=""></div></div><div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> extension <b class="">[T?]</b> {</span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> func unwrapAll() -> [T] { <font color="#919191" class="">/* ... */</font> }</span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> }</span></font></div><div class=""><div><br class=""></div><div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> extension <b class="">[K: [K: V]]</b> {</span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> subscript(x: K, y: K) -> V { </span></font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> }</span></font></div><div><span style="font-size: 11px; font-family: Menlo;" class=""> }</span></div><div class=""><font face="Menlo" class=""><span style="font-size: 11px;" class=""><br class=""></span></font></div></div><div>Here are a few more (somewhat realistically needed) examples with further `<font face="Menlo" style="font-size: 11px;" class="">where</font>` clauses:</div><div><br class=""></div><div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> extension <b class="">[T] where T : Hashable</b> { </span></font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> </span></font><span style="font-family: Menlo; font-size: 11px;" class="">}</span></div><div class=""></div></div><div></div></div></div><div><div><div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> extension <b class="">T? where T : Comparable</b> { </span></font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> </span></font><span style="font-family: Menlo; font-size: 11px;" class="">}</span></div><div class=""></div></div><div></div></div></div><div><div><div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> extension <b class="">[K: V] where V : Equatable</b> { </span></font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> </span></font><span style="font-family: Menlo; font-size: 11px;" class="">}</span></div></div></div></div><div><div><div><div><div class=""></div></div><div></div></div></div></div><div><div><div><div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> extension <b class="">[T] where T == String</b> { </span></font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> </span></font><span style="font-family: Menlo; font-size: 11px;" class="">}</span></div><div class=""></div></div><div></div></div></div><div><div><div><div></div></div></div></div></div><div><br class=""></div><div><div>I think pattern matching is a very expressive, intuitive, and readable technique that works quite well for this purpose, better than what we currently have.</div><div><br class=""></div><div><br class=""></div></div><div><b class=""><font size="4" class="">3. Future directions</font></b></div><div><br class=""></div><div>Brent already pointed out that the `<font face="Menlo" style="font-size: 11px;" class="">where</font>` constraint syntax could be used for dependent types (i.e. type-level values as generic parameters). Four more possible directions come to my mind:</div><div><br class=""></div><div>(1) Adding conditional protocol conformances:</div><div><br class=""></div><div><div><font face="Menlo" style="font-size: 11px;" class=""> extension [<b class="">T</b>]<b class="">: Equatable</b> where <b class="">T</b> : Equatable { </font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" style="font-size: 11px;" class=""> }</font></div><div class=""><div><font face="Menlo" style="font-size: 11px;" class=""> extension [<b class="">T</b>]<b class="">: Comparable</b> where <b class="">T</b> : </font><span style="font-family: Menlo; font-size: 11px;" class="">Comparable</span><font face="Menlo" style="font-size: 11px;" class=""> { </font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" style="font-size: 11px;" class=""> }</font></div><div class=""></div><div><font face="Menlo" style="font-size: 11px;" class=""> extension [<b class="">K</b>, <b class="">V</b>]<b class="">: Equatable</b> where <b class="">V</b> : Equatable { </font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" style="font-size: 11px;" class=""> }</font></div></div><div><font face="Menlo" style="font-size: 11px;" class=""> extension Foo<<b class="">X</b>, Bar<<b class="">Y</b>>> <b class="">: Bazzable</b> where <b class="">X</b> : Baz, <b class="">Y</b> : Baz</font><font face="Menlo" style="font-size: 11px;" class=""> { </font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" style="font-size: 11px;" class=""> }</font></div><div class=""><font face="Menlo" style="font-size: 11px;" class=""><br class=""></font></div></div><div>(2) Extending non-nominal types:</div><div><br class=""></div><div><div><font face="Menlo" style="font-size: 11px;" class=""> extension <b class="">(A, B)</b> { var tail: B { </font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" style="font-size: 11px;" class=""> }}</font></div><div class=""><div><font face="Menlo" style="font-size: 11px;" class=""> extension <b class="">(A, B, C)</b> { var tail: (B, C) { </font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" style="font-size: 11px;" class=""> }}</font></div></div><div class=""><br class=""></div></div><div>(3) Using variadic patterns (shamefully borrowing the `<font face="Menlo" style="font-size: 11px;" class="">...</font>` notation from C++ here to mean an arbitrary-length list of patterns to match or expressions to expand):</div><div><br class=""></div><div><div><font face="Menlo" style="font-size: 11px;" class=""> extension <b class="">(T...) : Equatable where T : Equatable...</b> {</font><font face="Menlo" style="font-size: 11px;" class="">}</font></div><div><font face="Menlo" style="font-size: 11px;" class=""><br class=""></font></div><div><font face="Menlo" style="font-size: 11px;" class=""> func == <b class=""><T...></b>(lhs: <b class="">(T...)</b>, rhs: <b class="">(T...)</b>) -> Bool <b class="">where T : Equatable...</b> {</font><font face="Menlo" style="font-size: 11px;" class=""> </font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/* ... */</span><font face="Menlo" style="font-size: 11px;" class=""> </font><font face="Menlo" style="font-size: 11px;" class="">}</font></div><div><br class=""></div><div>(4) Since all type constraints with `<font face="Menlo" style="font-size: 11px;" class="">:</font>` fly out to of the generic parameter list into the `<font face="Menlo" style="font-size: 11px;" class="">where</font>` clause, we could enable the use of colons to give labels to generic parameters (and thus even make some of them have default values):</div><div><br class=""></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> struct Parser<<b class="">encoding:</b> Encoding, <b class="">input:</b> Input></span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> where Encoding : EncodingProtocol </span></font><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">/*, ... */</span></div><div><span style="font-size: 11px; font-family: Menlo;" class=""> {</span></div><div><span style="font-family: Menlo; font-size: 11px;" class=""> </span><span style="color: rgb(145, 145, 145); font-family: Menlo; font-size: 11px;" class="">// ...</span></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""><font color="#919191" class=""> </font>}</span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""><br class=""></span></font></div><div><font face="Menlo" class=""><span style="font-size: 11px;" class=""> let parser = Parser<<b class="">encoding:</b> UTF8, <b class="">input:</b> String>()</span></font></div><div><br class=""></div><div>— Pyry</div><div><br class=""></div></div></body></html>