<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">The nice thing about this setup is that it degrades nicely for the 1000-case enum. You have a static check in the compiler for if theNumberOfKnownEnumCases >= SOME_REASONABLE_MAX (or — in the future — as complicated a decision as you want given the number of total cases and the number of cases you care about in that particular switch) then you pass in an array of just the switched against cases instead, and the implementation of indexForMyOpaqueEnumTag() remains exactly the same in the callee (the early out matching count fails, and you binary search).<div class=""><br class=""><div>- Greg</div><div><br class=""><blockquote type="cite" class=""><div class="">On Oct 12, 2017, at 3:38 PM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">Our worry when discussing it was that someone might have an autogenerated 1000-case enum, and passing an entire page worth of resolved symbols might not be worth it.</div><div class=""><br class=""></div><div class="">(It is of course questionable for someone to have an autogenerated 1000-case enum as part of their binary interface, and then for someone to try to switch over it. But matching against one or two of the cases shouldn't be as expensive as matching against all 1000 known cases.)</div><div class=""><br class=""></div><div class="">Jordan</div><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Oct 12, 2017, at 15:20, Greg Titus <<a href="mailto:greg@omnigroup.com" class="">greg@omnigroup.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">I like Joe’s idea here, with the extension that the client should have just one of these arrays that contains all the symbols that it knows about at the time it was compiled:<div class=""><br class=""></div><div class="">I.e. in the client:</div><div class=""><br class=""></div><div class="">static myKnownOpaqueEnumCases = [MyOpaqueEnum.intCase, MyOpaqueEnum.middleCase, MyOpaqueEnum.stringCase];</div><div class=""><br class=""></div><div class="">switch indexForMyOpaqueEnumTag(&myOpaqueEnum, myKnownOpaqueEnumCases) {</div><div class="">case 0: //…</div><div class="">case 2: //…</div><div class="">default: //...</div><div class="">}</div><div class=""><br class=""></div><div class="">This optimizes for space in the client, because you have one array instead of one per potentially-different-sets-of-cases switch, but more importantly this allows for an optimization inside indexForMyOpaqueEnumTag(). If the count of the array passed in from the client is equal to the count of all known cases in the callee, then you can immediately return the internal enum tag value instead of performing a binary search.</div><div class=""><br class=""></div><div class="">(If the client expects cases that the callee doesn’t have, the link would have failed for a missing symbol, if the callee has more cases the count won’t match, so if the count is equal the cases in both object files have to be identical.) This returns the common runtime case (when the client is up to date with the callee) to being O(1).</div><div class=""><br class=""></div><div class="">The cost being, if you don’t take that fast path, maybe you have a few more entries in the cases array to binary search over than that particular switch statement needed.</div><div class=""><div class=""><br class=""></div><div class="">- Greg</div><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Oct 12, 2017, at 2:25 PM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">So, an update! This came up while I was talking to members of the core team, and ChrisL felt very strongly that restricting reordering of enum elements was a no-go, since it would be the only part of the language that worked this way (even if it only mattered for binary frameworks). Ted also rightly pointed out that any such language-level restriction would have to be reviewed by the core team.<div class=""><br class=""></div><div class="">So where does that leave us?</div><div class=""><br class=""></div><div class="">- The naive implementation is to turn a switch into an if-else chain, unfortunately requiring one function call per case to match.</div><div class=""><br class=""></div><div class="">- A slightly more complex solution keeps a single 'getMyOpaqueEnumTag' entry point (see original email), but exposes symbols for every tag. The values of the symbols would be kept in alphabetical order, which allows the generated code to do a binary search over the cases they care about. This still means N symbols, but a switch that involves several of them doesn't necessarily have to take linear time.</div><div class=""><br class=""></div><div class="">- Joe Groff came up with this idea that also involves sorted symbols:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">switch indexForMyOpaqueEnumTag(&myOpaqueEnum, [MyOpaqueEnum.intCase, MyOpaqueEnum.stringCase]) {</div><div class="">case 0:</div><div class=""> var payload: Int</div><div class=""> getMyOpaqueEnumPayload(&myOpaqueEnum, MyOpaqueEnum.intCase, &payload)</div><div class=""> doSomething(payload)</div><div class="">case 1:</div><div class=""> var payload: String</div><div class=""> getMyOpaqueEnumPayload(&myOpaqueEnum, MyOpaqueEnum.stringCase, &payload)</div><div class=""> doSomethingElse(payload)</div><div class="">default:</div><div class=""> print("unknown case")</div><div class="">}</div></blockquote><div class=""><br class=""></div><div class="">In this example, the actual tag values for 'intCase' and 'stringCase' might not be 0 and 1, but 'indexForMyOpaqueEnumTag' can do the binary search to find out which enum we're asking for. Like the previous solution, you only have to check the cases you care about, but this time the binary search is in the callee, rather than the client.</div><div class=""><br class=""></div><div class="">- Use availability ordering, plus some kind of explicit annotation for when multiple cases are added within the same release. (In this thread people have suggested dates, ad-hoc sub-version numbers, and plain integer values.)</div><div class=""><br class=""></div><div class="">I appreciate everyone's creativity with solving the availability ordering problem, but I don't want to tie us to a checker that will tell you if you screw up or a history scraper that will implicitly add the right annotations. (I don't think those are bad ideas, but they're a whole extra pile of work on top of the main implementation!) That leaves explicit annotations of some kind, and that leaves us in a worse place than Objective-C. Which is <i class="">permitted,</i> but not desirable.</div><div class=""><br class=""></div><div class=""> At this point in time I think the second option is the best one we have: it's relatively simple to implement, it supports everything Objective-C does, and it doesn't make the availability model even <i class="">more</i> complicated. It <i class="">is</i> going to be less efficient than actually knowing the case numbers at compile time, though. Still, as Slava's pointed out, we can still change this after we go ABI-stable; doing something more efficient will just be limited based on deployment target.</div><div class=""><br class=""></div><div class="">Jordan</div><div class=""><br class=""></div></div></div></blockquote></div><br class=""></div></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></div></body></html>