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
