<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=""><div><blockquote type="cite" class=""><div class="">On Nov 13, 2017, at 9:21 PM, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" class="">xiaodi.wu@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><span style="font-family: Helvetica; font-size: 12px; 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; float: none; display: inline !important;" class="">...I should add, if full conformance to `Collection` is still too much to ask, enabling "for `case` in Foo.self" by magic would itself address the entirety of the proposal's use case, adding no API surface area.</span></div></blockquote></div><div class=""><br class=""></div><div class="">No, Xiaodi. No, it would not.</div><div class=""><br class=""></div><div class="">Okay, thus far we've talked vaguely about "accessing the cases of an enum", but let's talk a little more concretely about what that means. I think that, especially on Apple platforms, this is the most important concrete use case:</div><div class=""><br class=""></div><div class="">PROBLEM:</div><div class=""><br class=""></div><div class="">You have an enum like:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>enum BugStatus {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>case open, inProgress, resolved, closed, reopened</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var localizedName: String { … }&nbsp;</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class=""><br class=""></div><div class="">You wish to present these options in a user interface so a user can select one of them. For instance, if you're on iOS and using UITableView, you might want to present the enum's values through `UITableViewDataSource` and allow selection through `UITableViewDelegate`.</div><div class=""><br class=""></div><div class="">REQUIREMENTS:</div><div class=""><br class=""></div><div class="">1. It must be possible to easily access the count of values, and to access any particular value using contiguous `Int` indices. This could be achieved either by directly accessing elements in the list of values through an Int subscript, or by constructing an Array from the list of values.</div><div class=""><br class=""></div><div class="">2. It must be possible to control the order of values in the list of values, either by using source order or through some other simple, straightforward mechanism.</div><div class=""><br class=""></div><div class="">PROPOSED SOLUTION:</div><div class=""><br class=""></div><div class="">You conform `BugStatus` to `ValueEnumerable`:</div><div class=""><br class=""></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>enum BugStatus: ValueEnumerable {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>case open, inProgress, resolved, closed, reopened</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var localizedName: String { … }&nbsp;</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div></div><div class=""><br class=""></div><div class="">And then write the table view data source to present the elements of `BugStatus.allValues`:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>class BugStatusDataSource: NSObject, UITableViewDataSource, UITableViewDelegate {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>@IBOutlet&nbsp;var tableView: UITableView?</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span></div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>@objc dynamic&nbsp;var selected: BugStatus? {<span class="Apple-tab-span" style="white-space:pre">                </span>// Observable via KVO</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>didSet {&nbsp;tableView.reloadData() }</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span></div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func status(at indexPath: IndexPath) -&gt; Status {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>BugStatus.allValues[indexPath.row]</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span></div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func tableView(_: UITableView, numberOfRowsInSection section: Int) -&gt; Int {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>return BugStatus.allValues.count</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span></div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func tableView(_: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>let status = self.status(at: indexPath)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>let identifier = (status == selected) ? "SelectedCell" : "RegularCell"</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span></div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>cell.titleLabel.text = status.localizedName</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return cell</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span></div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>selected = status(at: indexPath)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class=""><br class=""></div><div class="">This is the most direct solution; a more sophisticated version might inject the list as an Array so that you can show a subset of the full set of values.</div><div class=""><br class=""></div><div class="">EXTENSIONS:</div><div class=""><br class=""></div><div class="">Now, let's quickly talk about a couple extensions of this use case:</div><div class=""><br class=""></div><div class="">* The values, and the table view cells, are grouped into sections. This suggests some sort of two-level, nested structure, which may not use `Int` indices.</div><div class=""><br class=""></div><div class="">* You want to write a *generic* data source which can present all the values of *any* ValueEnumerable type (or at least any conforming to a protocol that allows us to fill in their cells). For that purpose, it's helpful to have the type conform to *some* sort of protocol and expose the value list through that protocol.</div><div class=""><br class=""></div><div class="">You say that:</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><span class="" style="float: none; display: inline !important;">&nbsp;</span>Essentially all other uses for enumeration of enum cases can be trivially recreated based on just that.</blockquote></div><div class=""><br class=""></div><div class="">But with this use case in mind, we can see that it is "trivial" in the sense that the annoying boilerplate you need to bridge the significant impedance mismatch is easy to come up with. Yes, you could construct an array using the magic `for` loop, but that would be a serious pain. (And there would be no ergonomic, mistake-resistant way to hide that pain behind a function/initializer call, because there's no way to say that a parameter must be a metatype for an enum.) What you really want is a way to access or construct an `Array` or array-like type containing the type's values.</div><div class=""><br class=""></div><div class="">*Actually* conforming the metatype to `Sequence` or `Collection` would be a different story. There, you could construct `Array`s or access elements using ordinary APIs and type system features. And you could write generic algorithms which used the set of all types: they would require conformance to `Sequence` or `Collection`, and users would specify `Foo.Type` as the generic parameter. But I suspect that would require deeper compiler changes than we can be certain to get in Swift 5 or really at any specific point on the roadmap, and I don't think we should delay this feature indefinitely to get a design whose only real benefit is elegance.</div><br class=""><div class="">
<span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;"><div class=""><div style="font-size: 12px; " class="">--&nbsp;</div><div style="font-size: 12px; " class="">Brent Royal-Gordon</div><div style="font-size: 12px; " class="">Architechies</div></div></span>

</div>
<br class=""></body></html>