Hi Jordan, Bertrand (ex-Apple) would sometimes say during API design that “easy things things should be easy, and hard things should be possible”.
I don’t think you guys need to go out of your way to make the autogenerated 1000-case enum scenario “easy". If people are clever enough to do that, then they can surely handle the fallout of this change. :-) Dave > On Oct 12, 2017, at 18:38, Jordan Rose via swift-dev <swift-dev@swift.org> > wrote: > > 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. > > (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.) > > Jordan > >> On Oct 12, 2017, at 15:20, Greg Titus <g...@omnigroup.com >> <mailto:g...@omnigroup.com>> wrote: >> >> 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: >> >> I.e. in the client: >> >> static myKnownOpaqueEnumCases = [MyOpaqueEnum.intCase, >> MyOpaqueEnum.middleCase, MyOpaqueEnum.stringCase]; >> >> switch indexForMyOpaqueEnumTag(&myOpaqueEnum, myKnownOpaqueEnumCases) { >> case 0: //… >> case 2: //… >> default: //... >> } >> >> 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. >> >> (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). >> >> 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. >> >> - Greg >> >>> On Oct 12, 2017, at 2:25 PM, Jordan Rose <jordan_r...@apple.com >>> <mailto:jordan_r...@apple.com>> wrote: >>> >>> 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. >>> >>> So where does that leave us? >>> >>> - The naive implementation is to turn a switch into an if-else chain, >>> unfortunately requiring one function call per case to match. >>> >>> - 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. >>> >>> - Joe Groff came up with this idea that also involves sorted symbols: >>> >>> switch indexForMyOpaqueEnumTag(&myOpaqueEnum, [MyOpaqueEnum.intCase, >>> MyOpaqueEnum.stringCase]) { >>> case 0: >>> var payload: Int >>> getMyOpaqueEnumPayload(&myOpaqueEnum, MyOpaqueEnum.intCase, &payload) >>> doSomething(payload) >>> case 1: >>> var payload: String >>> getMyOpaqueEnumPayload(&myOpaqueEnum, MyOpaqueEnum.stringCase, &payload) >>> doSomethingElse(payload) >>> default: >>> print("unknown case") >>> } >>> >>> 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. >>> >>> - 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.) >>> >>> 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 permitted, but not desirable. >>> >>> 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 more complicated. It >>> is 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. >>> >>> Jordan >>> >> > > _______________________________________________ > swift-dev mailing list > swift-dev@swift.org > https://lists.swift.org/mailman/listinfo/swift-dev
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev