<div dir="ltr">Hey folks! <div><br></div><div>Thanks for all the great feedback and discussion. <div>I really like Tony&#39;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&#39;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&#39;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 &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; 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&#39;ve been waiting for this for years. Literally since Swift was announced. IMO it&#39;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&#39;d guess, others) would expect.</div><div><span class="m_7810726130120944094Apple-tab-span" style="white-space:pre-wrap">        </span>- Every time I&#39;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&#39;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..............&lt;count, but I do imagine it&#39;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&#39;t that what raw value enums are for? If the user needs to do what you&#39;re saying—map specific integers to enum values—shouldn&#39;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&#39;re missing is being able to retrieve the count, which a &quot;PrecountedSequence&quot; 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&#39;t think of why someone would do that, but I&#39;m happy to consider something that I&#39;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&#39;t fully considering. If other invariants in the application hold—such as table view cell functions never receiving a section index outside 0..&lt;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>