<div dir="ltr">Hey folks! <div><br></div><div>Thanks for all the great feedback and discussion. <div>I really like Tony's suggestion of the opt-in ValueEnumerable protocol.</div><div>However, I think Kevin is right that it should be a simple array. </div><div>If we wanted to get fancy, we could implement a custom integer indexed</div><div>collection that indexed into the type's memory to provide a random</div><div>access collection of cases without allocating any new memory.</div><div>This does seem more complex than just synthesizing the array as</div><div>an opt-in, though.</div><div><br></div><div>I also agree that it should be in declaration order. If the user wants to</div><div>have integer enums in ascending order they can write an extension</div><div>that sorts allCases. And I think this should absolutely not work for</div><div>associated values. You can implement the protocol if you want,</div><div>but you don't get anything synthesized for you.</div><div><br></div><div>Best,</div><div>Logan</div><br><div class="gmail_quote"><div dir="ltr">On Fri, Sep 8, 2017 at 11:49 AM Kevin Nattinger via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">I've been waiting for this for years. Literally since Swift was announced. IMO it's one of several major gaps in the language.<div><br></div><div>Some thoughts:</div><div>- It should be a simple array. </div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- By far the most simple solution, and the one I (and, I'd guess, others) would expect.</div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- 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).</div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- In my experience, direct indexing into the values array is more common than iterating over it.</div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- Rarely more than a few cases.</div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- Even an enum with a lot of cases, the actual number is trivial compared to the program's memory usage.</div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- 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?</div><div>- It should always be in declaration order. Period. </div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- 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.</div><div>- Should only work on enums without associated values. Enumerating on associated values is just begging for trouble. </div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- (Infinite) recursion, as you pointed out.</div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- It seems more intuitive to me to have enumerated cases grouped, but what if there are cases with and without ATs?</div><div><br></div></div><div style="word-wrap:break-word"><div><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><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"><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_quote"><div><font color="#000000">[...]</font></div></div></div></div></blockquote></div></div></blockquote></div></div></div></blockquote><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><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"><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_quote"><div>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.</div></div></div></div></blockquote></div></div></blockquote></div></div></div></blockquote></div></div></div><div style="word-wrap:break-word"><div><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><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"><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_quote"><div><br></div><div>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.</div></div></div></div></blockquote></div></div></blockquote></div></div></div></blockquote></div></div></div><div style="word-wrap:break-word"><div><div>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 { ... }`)?</div></div></div><div style="word-wrap:break-word"><div><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><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"><div><div>First, I’m making observations about what people are doing, not what they could do. </div><div><br></div><div>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.</div></div></div></blockquote></div></div></div></blockquote></div></div></div><div style="word-wrap:break-word"><div><div>+1000. There is absolutely no reason to join these, or special-case 0-N int raw representables. </div></div></div><div style="word-wrap:break-word"><div><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_quote"><div>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.</div></div></div></div></blockquote></div></div></div><div style="word-wrap:break-word"><div><div><div>Some underlying meaning? E.g. not a table view, but values or identifiers for some sort of low-level protocol.</div><br></div></div></div><div style="word-wrap:break-word"><div><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><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"><div><div>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.</div></div></div></blockquote></div></div></div></blockquote></div></div></div><div style="word-wrap:break-word"><div><div><blockquote type="cite"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_quote"><div><br></div><div>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.</div></div></div></div></blockquote></div></div></div><div style="word-wrap:break-word"><div><div>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. </div></div></div>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div></div></div>