David, Yeah, that's what I'm worried about. I was meaning to ask some engineers about the implementation of this during WWDC (hence why I didn't send it out), but didn't get a chance to do so.
On Thu, Jun 30, 2016 at 2:09 PM David Waite <[email protected]> wrote: > On Jun 30, 2016, at 2:54 PM, Dan Appel via swift-evolution < > [email protected]> wrote: > > Paul, > > That is the current workaround (as the proposal mentions), but it is still > missing support for enum features such as associated values and the pattern > matching power that they bring. > > > I don’t believe a developer would be able to extend an enum to support > arbitrary associated values, the same as the limitation that one cannot > extend a type today to have extra members. Value types need to have an > understood size and structure at compile time of the file/module that they > are in. > > > > Dan > > On Thu, Jun 30, 2016 at 1:42 PM Paul Cantrell <[email protected]> wrote: > >> While it doesn’t give all the “raw value” functionality of enum, it’s >> possible to use object instance uniqueness to get enum-like behavior that >> can be extended: >> >> public protocol OpenEnum: class, Hashable { } >> >> extension OpenEnum { >> public var hashValue: Int { >> return ObjectIdentifier(self).hashValue >> } >> } >> >> public func ==<T: OpenEnum>(lhs: T, rhs: T) -> Bool { >> return lhs === rhs >> } >> >> A library can provide: >> >> public final class Color: OpenEnum, CustomStringConvertible { >> public let description: String >> >> public init(description: String) { >> self.description = description >> } >> >> static let >> black = Color(description: "black"), >> white = Color(description: "white") >> } >> >> And then in a client project: >> >> extension Color { >> static let >> puce = Color(description: "puce"), >> mauve = Color(description: "mauve"), >> fuchsia = Color(description: "fuchsia") >> } >> >> (This is how Siesta provides an extensible set of pipeline stages. >> https://github.com/bustoutsolutions/siesta/pull/64) >> >> With this approach, you still get the .member shortcut in some >> circumstances: >> >> let eyebleedPalette: [Color] = [.fuchsia, .black, .mauve] >> >> …but not in others: >> >> // Compiles >> switch(color) { >> case *Color*.red: print("Danger!") >> case *Color*.mauve: print("Dancing!") >> default: print("Nothing notable") >> } >> >> // Does not compile >> switch(color) { >> case .red: print("Danger!") >> case .mauve: print("Dancing!") >> default: print("Nothing notable") >> } >> >> Given that this already comes close to giving the sort of functionality >> one would want out of an extensible enum, perhaps it’s better to fill out >> the gaps in this approach instead of adding a new language feature? This >> would have the advantage of not adding a keyword, and presumably provide >> useful behaviors that generalize to patterns other than extensible enums. >> >> Cheers, >> >> Paul >> >> On Jun 30, 2016, at 3:23 PM, Guillermo Peralta Scura via swift-evolution < >> [email protected]> wrote: >> >> I think the approach taken by your proporsal is really good. Would love >> to have that feature for the language. >> >> El jue., 30 jun. 2016 a las 16:19, Edward Valentini via swift-evolution (< >> [email protected]>) escribió: >> >>> >>> I really like the idea of making it opt in with the extensible keyword >>> as opposed to opt out with final so this way there is no impact on existing >>> code >>> >>> On Jun 30, 2016, at 16:15, Dan Appel <[email protected]> wrote: >>> >>> I've had a draft of a proposal lying around for a while which addresses >>> exactly this, but I haven't gotten around to sending it out for comments >>> yet. Link >>> <https://gist.github.com/Danappelxx/41b7c2e86787f75698bd48135cc616f5>. >>> >>> Would appreciate if you guys took a look. >>> Dan Appel >>> >>> Pasted inline below >>> >>> Extensible Enums >>> >>> - Proposal: SE-NNNN >>> >>> <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md> >>> - Author: Dan Appel <https://github.com/danappelxx> >>> - Status: Awaiting review >>> >>> <https://gist.github.com/Danappelxx/41b7c2e86787f75698bd48135cc616f5#rationale> >>> - Review manager: TBD >>> >>> >>> <https://gist.github.com/Danappelxx/41b7c2e86787f75698bd48135cc616f5#introduction> >>> Introduction >>> >>> This proposal introduces a new keyword that can be applied to enums >>> which allows new cases to be introduced in extensions. >>> >>> Swift-evolution thread: [RFC] Extensible Enums >>> <https://lists.swift.org/pipermail/swift-evolution> >>> >>> <https://gist.github.com/Danappelxx/41b7c2e86787f75698bd48135cc616f5#motivation> >>> Motivation >>> >>> Enums are a powerful feature which provides a lot of benefit if you have >>> a limited number of behaviors. For example, associated values provide the >>> ability to make every case essentially a separate type. However, due to the >>> static nature of enums, they cannot be used in situations where they would >>> otherwise be a perfect fit. >>> >>> An example of this would be the use of an Error enum like so: >>> >>> enum FileError: ErrorProtocol { >>> case fileNotFound(path: String) >>> case corruptedFile(bytes: [Int8]) >>> }func readFile() throws { ... } >>> // elsewhere in the codebasedo { >>> try readFile() >>> } catch let error as FileError { >>> switch error { >>> case .fileNotFound(let path): // handle error >>> case .corruptedFile(let bytes): // handle error >>> } >>> } catch { ... } >>> >>> While this is generally a good approach, it can be very dangerous for >>> library consumers if the author exposes the error to the user. This is due >>> to the fact that the switch statement has to be exhaustive and is only >>> satisfied when all enum cases have been accounted for. What this means for >>> library authors is that every time they add a new case to a public enum, >>> they are breaking the exhaustivity of the switch and making their >>> library backwards-incompatible. >>> >>> Currently, the best workaround is to use a struct with static instances >>> and overloading the ~= operator. This allows for similar switch behavior >>> but overall is much less flexible, missing key features such as associated >>> values. >>> >>> Another example is when the library is split into multiple modules, >>> where the error is defined in the first module and the second module wants >>> to add some error cases. An enum is very rarely used in this case because >>> you cannot add cases in other modules. Instead, library authors either use >>> an error protocol, and add more types that conform to it, or use the struct >>> approach shown above. While this is not terrible, adding cases in >>> extensions would better translate the intention of the author and adds more >>> flexiblity. >>> >>> <https://gist.github.com/Danappelxx/41b7c2e86787f75698bd48135cc616f5#proposed-solution>Proposed >>> solution >>> >>> The solution proposed is quite simple: add an extensible keyword/modifier >>> that can be applied to enums, which would require the default case when >>> switched on and allow new cases to be added in extensions. >>> >>> Here is the translation of the very first example to the use an >>> extensible enum instead, with a new case added: >>> >>> extensible enum ThingError: ErrorProtocol { >>> case fileNotFound(path: String) >>> case corruptedFile(bytes: [Int8]) >>> case failedReadingFile >>> }func readFile() throws { ... } >>> // elsewhere in the codebasedo { >>> try readFile() >>> } catch let error as ThingError { >>> switch error { >>> case .fileNotFound(let path): // handle error >>> case .corruptedFile(let bytes): // handle error >>> default: // handle future errors that don't exist yet >>> } >>> } catch { ... } >>> >>> For the second example, we can simply extend the enum in the >>> higher-level module. >>> >>> // Module FileProtocol >>> >>> extensible enum FileError: ErrorProtocol { >>> case fileNotFound(path: String) >>> } >>> protocol FileProtocol { >>> func read() throws >>> } >>> // Module File >>> extension FileError { >>> case corruptedFile(bytes: [Int8]) >>> case failedReadingFile >>> } >>> struct File: FileProtocol { >>> func read() throws { ... } >>> } >>> >>> >>> <https://gist.github.com/Danappelxx/41b7c2e86787f75698bd48135cc616f5#detailed-design>Detailed >>> design >>> >>> A new keyword would be added to the language which is only allowed in >>> front of the enum keyword. When an enum is marked extensible, new cases >>> can be added in extensions and switches that are performed on it require a >>> defaultcase. >>> >>> <https://gist.github.com/Danappelxx/41b7c2e86787f75698bd48135cc616f5#impact-on-existing-code>Impact >>> on existing code >>> >>> There is no impact on existing code since this is purely an additive >>> feature. >>> >>> <https://gist.github.com/Danappelxx/41b7c2e86787f75698bd48135cc616f5#alternatives-considered>Alternatives >>> considered >>> >>> No alternatives have been considered (yet). >>> >>> >>> >>> On Thu, Jun 30, 2016 at 1:04 PM David Sweeris via swift-evolution < >>> [email protected]> wrote: >>> >>>> By itself, this would break switch statements, since they have to be >>>> exhaustive. >>>> >>>> If anyone has any ideas about how to fix that, I'm all ears. >>>> >>>> - Dave Sweeris >>>> >>>> > On Jun 30, 2016, at 14:58, Edward Valentini via swift-evolution < >>>> [email protected]> wrote: >>>> > >>>> > >>>> > I am finding myself in a situation where the most elegant "swifty" >>>> solution would be to allow enum extensions to add to existing case >>>> options. For example lets say I'm using a library that has the following >>>> enum defined: >>>> > >>>> > enum MyDirection { >>>> > case east, west >>>> > } >>>> > >>>> > My app for example also makes use of north and south, so I would love >>>> to be able to write: >>>> > >>>> > extension MyDirection { >>>> > case north,south >>>> > } >>>> > >>>> > In objective c, one would probably have defined constants like >>>> MyDirectionEast etc... these would probably have been mapped to ints or >>>> strings so a consumer of this library could have easily extended this to >>>> add additional functionality, but using constants like that is not very >>>> "swifty" >>>> > >>>> > I'm curious what the swift community thinks. >>>> > >>>> > Thank you >>>> > _______________________________________________ >>>> > swift-evolution mailing list >>>> > [email protected] >>>> > https://lists.swift.org/mailman/listinfo/swift-evolution >>>> _______________________________________________ >>>> swift-evolution mailing list >>>> [email protected] >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> >>> -- >>> Dan Appel >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> >> -- > Dan Appel > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution > > -- Dan Appel
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
