[swift-evolution] [swift-dev] Re-pitch: Deriving collections of enum cases

Jonathan Hull jhull at gbis.com
Sat Dec 9 20:26:34 CST 2017


> On Nov 14, 2017, at 9:06 PM, Brent Royal-Gordon via swift-dev <swift-dev at swift.org> wrote:
> 
>> On Nov 14, 2017, at 5:21 PM, Xiaodi Wu <xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>> wrote:
>> 
>> 1. It must be possible to easily access the count of values, and to access any particular value using contiguous `Int` indices. This could be achieved either by directly accessing elements in the list of values through an Int subscript, or by constructing an Array from the list of values.
>> 
>> 2. It must be possible to control the order of values in the list of values, either by using source order or through some other simple, straightforward mechanism.
>>  
>> OK, first of all, nowhere in the proposal text are these requirements stated as part of the use case. You're free to put forward new use cases, but here I am trying to design the most elegant way to fulfill a stated need and you're telling me that it's something other than what's written.
> 
> Honestly, re-reading the proposal, it never cites a fully-formed use case. Instead, it cites several blog posts, Stack Overflow questions, and small code samples without digging in to the underlying reasons why developers are doing what they're doing. Most of the people discussing it so far seem to have had a tacit understanding that we wanted roughly Array-like access, but we haven't explicitly dug into which properties of an Array are important.
> 
> (If anyone involved feels like they had a different understanding of the use case, please speak up.)
> 
> I think this is a place where the proposal can be improved, and I'm willing to do some writing to improve it.


This is a feature I have been requesting since Swift 1.  If the resulting ordering is not SOURCE ordering, this feature loses most of it’s usefulness for me. I would say around 80% of my uses for this require a predictable ordering (and I don’t consider something based on compiler internals predictable) which I can control.  As Brent said, most of those cases involve something that shows to the user in some way.  The weekday example was a good one (I actually have that in my code).  

The most painful case of this being missing was where I needed an enum of all country codes (it is a beast to maintain).  In that case, I am displaying them to the user in a tableView (along with icons named by the country codes), but I am also filtering them based on the user’s input in a search field.  To do both, you need to be able to iterate/filter an array of cases. Awful to build. Just awful.

Also, I would greatly prefer an allValues/allCases method to having the type be a collection. It just reads clearer in code what is going on.  I think what I basically want to see is:

	protocol ValueEnumerable {
		var allValues:Collection<Self>
	}

…where both the conformance and implementation are automatically inferred for enums when possible.

I would probably also end up using this protocol on Structs that I use as extensible enums.  That is, I have a private/internal initializer and use static vars in place of the cases.  This isn’t perfect, since part of the reason I use these structs is that they can be built in a distributed way… but I could find a way to build that array in a mostly distributed way as well (and if we ever get the Multi-function capability I have suggested elsewhere, then it could be truly distributed).

Semantically, the protocol should infer not only a finite number of cases, but a number that can be iterated over in a reasonable period of time.  I would be fine with Bool conforming, but not with Int.  With those semantics, I could easily see a follow-on proposal which says that associated cases where all of the values are ValueEnumerable are ValueEnumerable themselves.  This would be super useful for cascading enums.  I have a game that I am working on in my spare time right now, where effects of actions are represented as enums, with a single enum for all effects that references more specific enums for each type of thing that can be affected.


One other common need which I feel I should bring up even though it is a bit tangential, is that when I have enums with associated values, 90% of the time, I end up wanting a way to refer to the base of that without the value.  For example, if the player has a case called ‘damage’ which has an associated Int, I end up wanting to ask (and sometimes store) if the case is a ‘damage’ case.  Often, I am trying to match against patterns: Were there two damages followed by a block?  What I end up doing is creating a second enum with the same cases (sans values) and then creating a mapping between the two. Busywork in the same way writing these allValues arrays are busywork.  If we end up creating a way to reference just the base, maybe the allValues array should just contain those bases for non-enumerable associated values. Food for thought.

Thanks,
Jon


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171209/9d3ae6f3/attachment.html>


More information about the swift-evolution mailing list