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.
> 
> Would appreciate if you guys took a look.
> Dan Appel
> 
> Pasted inline below
> 
> Extensible Enums
> Proposal: SE-NNNN
> Author: Dan Appel
> Status: Awaiting review
> Review manager: TBD
> 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
> 
> 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 codebase
> do {
>     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.
> 
> 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 codebase
> do {
>     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 { ... }
> }
> 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.
> 
> Impact on existing code
> 
> There is no impact on existing code since this is purely an additive feature.
> 
> 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

Reply via email to