[swift-evolution] [Pitch] Synthesized static enum property to iterate over cases

Logan Shire logan.shire at gmail.com
Fri Sep 8 15:05:23 CDT 2017


Hey folks!

Thanks for all the great feedback and discussion.
I really like Tony's suggestion of the opt-in ValueEnumerable protocol.
However, I think Kevin is right that it should be a simple array.
If we wanted to get fancy, we could implement a custom integer indexed
collection that indexed into the type's memory to provide a random
access collection of cases without allocating any new memory.
This does seem more complex than just synthesizing the array as
an opt-in, though.

I also agree that it should be in declaration order. If the user wants to
have integer enums in ascending order they can write an extension
that sorts allCases. And I think this should absolutely not work for
associated values. You can implement the protocol if you want,
but you don't get anything synthesized for you.

Best,
Logan

On Fri, Sep 8, 2017 at 11:49 AM Kevin Nattinger via swift-evolution <
swift-evolution at swift.org> wrote:

> I've been waiting for this for years. Literally since Swift was announced.
> IMO it's one of several major gaps in the language.
>
> Some thoughts:
> - It should be a simple array.
> - By far the most simple solution, and the one I (and, I'd guess, others)
> would expect.
> - Every time I've needed the count, I need the actual values either within
> the same method or within the same run loop (e.g. table view).
> - In my experience, direct indexing into the values array is more common
> than iterating over it.
> - Rarely more than a few cases.
> - Even an enum with a lot of cases, the actual number is trivial compared
> to the program's memory usage.
> - No compiler magic beyond spitting out the static array. How do you
> propose to generate on-demand a sequence of values without compiler magic
> and without the values being stored somewhere?
> - It should always be in declaration order. Period.
> - Reordering only in the case of Int raw values (especially only when 0-N
> are all covered) is unintuitive at best, and I expect rarely what the dev
> would want.
> - Should only work on enums without associated values. Enumerating on
> associated values is just begging for trouble.
> - (Infinite) recursion, as you pointed out.
> - It seems more intuitive to me to have enumerated cases grouped, but what
> if there are cases with and without ATs?
>
> [...]
>>
>> Great points! I was only considering the table view/section case where
>> the enum had raw values 0..............<count, but I do imagine it's
>> possible that someone could just define `enum Section { case header,
>> content, footer }` and then want to turn an IndexPath value into the
>> appropriate Section.
>>
>>
>> On the other hand, though, isn't that what raw value enums are for? If
>> the user needs to do what you're saying—map specific integers to enum
>> values—shouldn't they do so by giving those cases raw values and calling
>> init?(rawValue:), not by indexing into a collection? Especially since they
>> can already do that today, and the only thing they're missing is being able
>> to retrieve the count, which a "PrecountedSequence" mentioned above, or
>> something like it, could also provide.
>>
>> I... guess one could do that? Seems undesirable to me. What if I have
> them explicitly numbered, and delete one? Oops, now the whole thing is off
> and I have to go fix all the numbers. Besides, what if the dev wants to use
> it as a different raw representable? (`enum Title: String { ... }`)?
>
> First, I’m making observations about what people are doing, not what they
>> could do.
>>
>> Second, the raw value may not correspond to 0-based indices.  It might
>> not even be an Int.  There is no reason to couple this common use case of
>> `allValues` to `Int` raw values with 0-based indices.
>>
> +1000. There is absolutely no reason to join these, or special-case 0-N
> int raw representables.
>
> Do we know of any examples where a user is both (1) defining an enum with
> integer raw values that are noncontiguous or non-zero-based and (2) need
> declaration-ordinal-based indexing into those cases for other reasons, like
> a table/collection view? I can't think of why someone would do that, but
> I'm happy to consider something that I'm missing.
>
> Some underlying meaning? E.g. not a table view, but values or identifiers
> for some sort of low-level protocol.
>
> Third, `init(rawValue:)` is a failable initializer and would require a
>> force unwrap.  If the raw values *are* 0-based integers this is similar to
>> the collection bounds check that would be necessary, but it moves it into
>> user code.  People don’t like writing force unwraps.
>>
>
> Yeah, this is a really good point that I wasn't fully considering. If
> other invariants in the application hold—such as table view cell functions
> never receiving a section index outside 0..<count—then unwrapping it just
> forces users to address a situation that will never actually occur unless
> UIKit is fundamentally broken.
>
> Or the user makes a mistake numbering cases, or forgets to update
> something, ... I usually put an assertion failure there, but I hate relying
> on even system libraries in production code.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170908/b3357178/attachment.html>


More information about the swift-evolution mailing list