<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><blockquote type="cite" class=""><div class="">On Apr 22, 2016, at 10:18 PM, Jacob Bandes-Storch <<a href="mailto:jtbandes@gmail.com" class="">jtbandes@gmail.com</a>> wrote:</div><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class=""><div class=""><div dir="ltr" class=""><div class="">On Sat, Apr 16, 2016 at 5:20 AM, plx via swift-evolution <span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span> wrote:<br class=""></div></div></div></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word" class=""><div class=""><span class=""><div class=""><br class=""></div></span><div class=""><br class=""></div><div class="">My 2c is that if this is to go in the standard library, it should be done “right”, which would be more like this version of it:</div><div class=""><br class=""></div><div class="">protocol ValueEnumerable {</div><span class=""><div class=""> associatedtype ValueCollection : Collection where ValueCollection.Iterator.Element == Self</div></span><div class=""> static var allValues: ValueCollection</div><div class="">}</div><div class=""><br class=""></div><div class="">…and that this concept should simply *wait* for that feature to be available before going into the standard library. </div><div class=""><br class=""></div><div class="">The reason I say this is simply b/c it sounds like this proposal wants to be able to support more than simple enumerations, in which case having some flexibility in the representation seems appropriate. Consider e.g.:</div><div class=""><br class=""></div><div class=""> struct AxisPolicy3D<Policy:protocol<Equatable,ValueEnumerable>> {</div><div class=""> var x: Policy</div><div class=""> var y: Policy</div><div class=""> var z: Policy</div><div class=""> }</div><div class=""><br class=""></div><div class=""> extension AxisPolicy3D : ValueEnumerable {</div><div class=""><br class=""></div><div class=""> static let allValues: ValueCollection = product(Policy.allValues,Policy.allValues,Policy.allValues).lazy.map() { </div><div class=""> (x,y,z) </div><div class=""> in</div><div class=""> AxisPolicy3D(x: x, y: y, z: z)</div><div class=""> }</div><div class=""><br class=""></div><div class=""> }</div><div class=""><br class=""></div><div class="">…and similar, wherein the cost of *requiring* an array here could become rather large.</div><div class=""><br class=""></div><div class="">But I have a couple general concerns here:</div><div class=""><br class=""></div><div class=""># Resiliency </div><div class=""><br class=""></div><div class="">My understanding is that the design for resiliency vis-a-vis enumerations is meant to allow enumerations to have cases added in future revisions (and perhaps also private cases? I didn’t follow resiliency closely). </div><div class=""><br class=""></div><div class="">If that’s right, and this protocol is supposed to go into the standard library, it might also need to address such issues. I have no help to offer and would love to be wrong about this point.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Thank you for bringing this up; I hadn't thought about it. Indeed, the library evolution design document <<a href="http://jrose-apple.github.io/swift-library-evolution/#enums" target="_blank" class="">http://jrose-apple.github.io/swift-library-evolution/#enums</a>> states that adding new cases, adding raw types, and reordering cases should be binary-compatible changes.</div><div class=""><br class=""></div><div class="">I hope someone who knows more about the resilience design can weigh in here. I'll CC Jordan Rose and John McCall, authors of that document, on this email.</div><div class=""><div class=""><br class="">I think you're right that the implications of requiring an array might be significant, if this array is exported as public API in a module which other binaries depend on. So I wonder if it might be possible to pursue a solution which <b class="">doesn't</b> export any additional public API in a module.</div><div class=""><br class=""></div><div class="">Recall that we'd like to be able to add ValuesEnumerable support in an extension, both on Swift enums and on enums imported from Obj-C. Seems like you might <b class="">not</b> want those conformances to be exported, so that future changes in the type of allValues wouldn't have to break existing compiled binaries. (But currently, IIUC, extensions which add protocol conformances must be public.)</div><div class=""><br class=""></div><div class="">I'm almost wondering whether we should be doing something like <b class="">#allValues(MyEnum)</b>, which uses # to indicate "compiler magic" (for now it would produce an Array<MyEnum>), gathering the available cases from the module at compile time. At some time in the future, when reflection is much more mature, perhaps this could be replaced with a standard library function.</div><div class=""><br class=""></div></div><div class="">---</div><div class=""><br class=""></div><div class="">This also prompted me to research Java's implementation a bit more. I'm not a Java user, let alone expert, but here's what I found:</div><div class=""><br class=""></div><div class="">Class.getEnumConstants() returns the values <b class="">in source order</b>. <<a href="https://docs.oracle.com/javase/tutorial/reflect/special/enumMembers.html" target="_blank" class="">https://docs.oracle.com/javase/tutorial/reflect/special/enumMembers.html</a>> The page also says the following: </div><div class=""><br class=""></div><div class=""><i class="">Note: For various reasons, including support for evolution of the enum type, the declaration order of enum constants is important. Class.getFields() and Class.getDeclaredFields() do not make any guarantee that the order of the returned values matches the order in the declaring source code. If ordering is required by an application, use Class.getEnumConstants().</i></div><div class=""> </div><div class="">There's also a section on "Evolution of Enums" in this page about Binary Compatibility: <<a href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.26" target="_blank" class="">https://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.26</a>> <i class="">"Adding or reordering constants in an enum type will not break compatibility with pre-existing binaries."</i></div><div class=""><br class=""></div><div class="">Point being that getEnumConstants() always returns an array, it just might have different things in it depending on the version of the class you're interrogating.</div><div class=""> </div><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word" class=""><div class=""><div class=""># Other Remarks</div><div class=""><br class=""></div><div class="">I see the `CaseEnumerable` discussion in the other discussion. It’s certainly related, but it’s something with enough independent utility I wouldn’t want it to get “lost” in this topic (especially since I think this topic is a great feature for the language, but one that may be awhile coming). </div></div></div></blockquote><div class=""><br class=""></div><div class="">CaseEnumerable was just an earlier name for Value(s)Enumerable. The stuff in the "Future directions" section remains speculative. I think we should keep the proposal focused if we want it to ever happen; improvements can come later.</div></div></div></div></div></blockquote><div><br class=""></div></div>I have not been following this discussion, but I would be extremely antsy about guaranteeing any particular representation for the set of values. Guaranteeing a contiguous array implementation seems like a really bad idea, especially if that's taken to mean that we're going to actually provide a static global array. But there's no way to avoid providing a public API, because a public conformance itself implies a public API with some level of corresponding overhead.<div class=""><br class=""></div><div class="">I don't remember the details of Java enums from my days as a Java programmer, but reading between the lines of your description, it sounds to me like Java originally made overly-strong guarantees that it decided to walk back in a later release. That's a lesson we should heed.<div class=""><br class=""></div><div class="">The interaction of resilience with enums is in principle quite straightforward: you ought to be able to arbitrarily change the set of stored cases for a resilient enum. That includes adding cases, changing existing cases to be "computed", and so on. (We haven't yet designed what it ought to mean for a case to be computed, but I assume it at least means providing an injector (Payload -> Enum) and a projector (Enum -> Payload?); whether and how to allow computed cases to factor into exhaustiveness checking is a separate but crucial question.) The fundamental problem for features like this is that adding a case with a payload is not compatible with actually being enumerable, outside of special cases and/or some formal-but-useless notion of recursive enumerability. But even if you couldn't add new cases with payloads (which is something we might consider adding as an intermediate opt-in constraint), and thus the type was necessarily finite, I can't imagine wanting to promise to return a static global array.</div><div class=""><div class=""><br class=""></div><div class="">John.</div></div></div></body></html>