> On Apr 22, 2016, at 10:18 PM, Jacob Bandes-Storch <jtban...@gmail.com> wrote:
> On Sat, Apr 16, 2016 at 5:20 AM, plx via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> 
> 
> 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:
> 
> protocol ValueEnumerable {
>   associatedtype ValueCollection : Collection where 
> ValueCollection.Iterator.Element == Self
>   static var allValues: ValueCollection
> }
> 
> …and that this concept should simply *wait* for that feature to be available 
> before going into the standard library. 
> 
> 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.:
> 
>   struct AxisPolicy3D<Policy:protocol<Equatable,ValueEnumerable>> {
>     var x: Policy
>     var y: Policy
>     var z: Policy
>   }
> 
>   extension AxisPolicy3D : ValueEnumerable {
> 
>     static let allValues: ValueCollection = 
> product(Policy.allValues,Policy.allValues,Policy.allValues).lazy.map() { 
>         (x,y,z) 
>         in
>         AxisPolicy3D(x: x, y: y, z: z)
>     }
> 
>   }
> 
> …and similar, wherein the cost of *requiring* an array here could become 
> rather large.
> 
> But I have a couple general concerns here:
> 
> # Resiliency 
> 
> 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). 
> 
> 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.
> 
> Thank you for bringing this up; I hadn't thought about it. Indeed, the 
> library evolution design document 
> <http://jrose-apple.github.io/swift-library-evolution/#enums 
> <http://jrose-apple.github.io/swift-library-evolution/#enums>> states that 
> adding new cases, adding raw types, and reordering cases should be 
> binary-compatible changes.
> 
> 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.
> 
> 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 doesn't export any additional public API in a module.
> 
> 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 not 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.)
> 
> I'm almost wondering whether we should be doing something like 
> #allValues(MyEnum), 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.
> 
> ---
> 
> 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:
> 
> Class.getEnumConstants() returns the values in source order.  
> <https://docs.oracle.com/javase/tutorial/reflect/special/enumMembers.html 
> <https://docs.oracle.com/javase/tutorial/reflect/special/enumMembers.html>> 
> The page also says the following: 
> 
> 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().
>  
> There's also a section on "Evolution of Enums" in this page about Binary 
> Compatibility: 
> <https://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.26 
> <https://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.26>>  
> "Adding or reordering constants in an enum type will not break compatibility 
> with pre-existing binaries."
> 
> 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.
>  
> 
> # Other Remarks
> 
> 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). 
> 
> 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.

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.

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.

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.

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to