<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 Jan 11, 2018, at 11:42 PM, Brent Royal-Gordon <<a href="mailto:brent@architechies.com" class="">brent@architechies.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Jan 11, 2018, at 4:21 PM, Paul Cantrell <<a href="mailto:cantrell@pobox.com" class="">cantrell@pobox.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" 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;">This raises a question related to Chris’s: what is the utility of having Limb conform to a protocol instead of just providing allValues ad hoc? Does CaseEnumerable / ValueEnumerable serve any purpose other than triggering special behavior in the compiler? Would the protocol ever be used as the type of something in code?</div><div class="" 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;"><br class=""></div><div class="" 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;">My answers, admittedly weak ones, are: (1) conventions are nice and consistency is nice, and (2) you never know how an abstraction might be used, but you do know that people will be angry when it should fit but doesn’t. I can’t come up with a more compelling or specific argument than those.</div></div></blockquote><br class=""></div><div class="">Here's a place where you might want to use the protocol: Suppose you're writing a table view data source that displays editable controls for a form. You support several different types of controls, one of which is a list of choices for a picker controller.</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>enum Control<Value> {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>case textField</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>case picker(choices: [Value])</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 makeView() -> UIView { … }</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>subscript(valueOf view: UIView) -> Value { get { … } set { … } }</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class=""><br class=""></div><div class="">Presumably you end up writing a schema which looks something like:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>formDataSource = FormDataSource(value: person)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>formDataSource.fields = [</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>Section(title: nil, fields: [</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>Field(title: "Name", keyPath: \.name, control: .textField),</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>Field(title: "Gender", keyPath: \.gender, control: . picker(choices: Array(Gender.allValues))),</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>]</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>tableView.dataSource = formDataSource</div><div class=""><br class=""></div><div class="">The `Array(Gender.allValues)` here is clutter; it'd be nice if we didn't have to write it explicitly. After all, if you're choosing a value of something you know is an enum, it's sensible to assume that you want to choose from all values if it doesn't specify anything more specific. If `ValueEnumerable` is a formalized protocol, you can do that with a constrained extension:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>extension Control where Value: ValueEnumerable {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>static var picker: Control {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>return .picker(choices: Array(Value.allValues))</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="">And now you just need to write:</div><div class=""><br class=""></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>Field(title: "Gender", keyPath: \.gender, control: . picker)</div></div></div></div></blockquote><div><br class=""></div><div>One magic future day, the protocol could be Chris’s narrower CaseEnumerable, Brent’s hypothetical picker could use a more general ValueEnumerable, and we could short-circuit the whole debate with:</div><div><br class=""></div><div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(88, 126, 168); background-color: rgb(255, 255, 255);" class=""><span style="color: #000000" class=""> </span><span style="color: #323e7d" class="">extension</span><span style="color: #000000" class=""> </span>CaseEnumerable<span style="color: #000000" class="">: </span>ValueEnumerable<span style="color: #000000" class=""> {</span></div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""> <span style="color: #323e7d" class="">var</span> allValues: WhateverThisTypeIsSupposedToBe {</div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""> <span style="color: #323e7d" class="">return</span> allCases</div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""> }</div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""> }</div></div><div><br class=""></div><div>…but I recall a particularly thorny “alternatives considered” section about the implications of allowing extensions to add protocol conformance to other protocols!</div><div><br class=""></div><div>Absent that language feature, I do think Brent has a point.</div><div><br class=""></div><div>I tend to agree with Chris’s assessment here, which to my eyes doesn’t contradict Brent’s example:</div><div><br class=""></div><div><blockquote type="cite" class="">On Jan 12, 2018, at 1:28 AM, Chris Lattner <<a href="mailto:clattner@nondot.org" class="">clattner@nondot.org</a>> wrote:</blockquote><div class=""><blockquote type="cite" class=""><br class=""></blockquote></div></div><div><blockquote type="cite" class=""><span style="font-family: HelveticaNeue;" class="">While we generally generally steer protocols towards being a “bag of semantics” instead of a “bag of syntax”, there are definitely exceptions to that rule, including the ExpressibleBy and other compiler intrinsic protocols which really are *all about* defining syntax. These protocols are not particularly useful for generic algorithms.</span><br style="font-family: HelveticaNeue;" class=""><br style="font-family: HelveticaNeue;" class=""><span style="font-family: HelveticaNeue;" class="">The next level down are protocols like hashable/comparable that are useful for generic algorithms, but are also particularly interesting because of compiler synthesized conformances. They are unique because they are both sometimes interesting for generic algorithms, but also sometimes interesting just because you want the synthesized members on *concrete* types for non-generic uses. IMO, this is the bucket that this proposal falls into.</span></blockquote></div><div><br class=""></div><div>That seems right: this CaseEnumerable / ValueEnumerable protocol will usually be about synthesized conformance, but occasionally be about semantics that are useful for generic algorithms.</div><div><br class=""></div><div>I wouldn’t want to touch the “all possible values for all types” idea with an ℵ₀-foot pole.[1] However, I don’t see the harm in going Brent’s direction: a protocol whose “bag of semantics” is along the lines of “has a limited, known set of possible values that does not change during execution, and that might reasonably be iterated over or displayed to the user as a set of choices.”</div><div><br class=""></div><div>That suggests to me the name ValueEnumerable. As with Equatable, it is named for the generic use, but synthesized by the compiler in a specific situation where it makes obvious sense to do so.</div><div><br class=""></div><div>Cheers, P</div><div><br class=""></div><div>[1] Surgeon general warning: cardinalities are not numbers. Do not use the Cantor hierarchy for measurement. Do not attempt to count to infinity. Do not shake hands with infinity. Do not approach an undomesticated infinity without approved protective gear. Stay safe out there.</div><div><br class=""></div><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><div class="">Basically, having `ValueEnumerable` be a formal protocol means we can extend this small automatic behavior into larger automatic behaviors. I can imagine, for instance, building a fuzzer which, given a list of `WritableKeyPath`s whose types are all `ValueEnumerable`, automatically generates random instances of a type and feeds them into a test function. If we get read-write reflection, we might be able to do this automatically and recursively. That'd be pretty cool.</div><div class=""><br class=""></div></div><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="">-- </div><div style="font-size: 12px; " class="">Brent Royal-Gordon</div><div style="font-size: 12px; " class="">Architechies</div></div></span>
</div>
<br class=""></div></blockquote></div><br class=""></body></html>