> 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