[swift-evolution] Allowing enum extensions to also be able to expand case options

Guillermo Peralta Scura gperaltascura at gmail.com
Thu Jun 30 15:23:04 CDT 2016


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 (<
swift-evolution at swift.org>) 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 <dan.appel00 at gmail.com> 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 <
> swift-evolution at swift.org> 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 <
>> swift-evolution at swift.org> 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
>> > swift-evolution at swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
> --
> Dan Appel
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160630/0148681a/attachment.html>


More information about the swift-evolution mailing list