> On Feb 7, 2017, at 1:44 PM, Tanner Nelson <[email protected]> wrote:
>
> To give a concrete example, some of the issues have arisen from using enums
> as Swift.Errors.
>
> ```
> public enum SocketError: Error {
> case closed
> }
> ```
>
> Then we find some new error that was unaccounted for and want to add a new
> case.
>
> ```
> public enum SocketError: Error {
> case closed
> case brokenPipe
> }
> ```
>
> What should have been a minor or possibly even a patch bump now requires a
> major bump.
>
> Looking back, it would have been easy to use a different data structure for
> these types of errors. But there's something so elegant about handling error
> enums like:
>
> ```
> do {
> try someSocketThing()
> } catch let error as SocketError {
> switch error {
> case .closed:
> print("the socket closed")
> default:
> print("there was an error with the socket")
> }
> }
> ```
>
> In this situation, a sensible default is easy and expected.
>
> On the other hand, something like the following obviously should be closed
> and allow exhaustive switching.
>
> ```
> public enum AutonomousCarAction {
> case turnLeft
> case turnRight
> }
> ```
>
> What I'm getting at here is I think it makes a lot of sense to allow the
> library developer to choose open or closed. I'd lean toward closed being the
> default since it seems to be the safer option--at least in terms of
> applications at runtime. Adding new options to a closed enum will cause the
> code not to compile, but at least consumers of the API aren't forced into
> adding "I don't know what to do here" default cases.
>
This kind of enum usage is a common source of API fragility. A potential
workaround is to use a struct. E.g.:
public struct SocketError: Error {
let id: Int
private init(_ id: Int) { self.id = id }
// .. common functionality goes here
static let broken: SocketError { return SocketError(0) }
static let closed: SocketError { return SocketError(1) }
...
}
And the use site would be:
do {…}
catch let error as SocketError {
if error == .broken {
…
} else {
… default handling ...
}
}
(this is very similar to how the NS_[EXTENSIBLE]_ENUMs are imported into Swift;
you get layout-equivalent with C for free)
Another alternative is to have “SocketError” be a protocol, and “BrokenPipe” be
an uninhabitable type that conforms to it (i.e. case-less enum). Such errors
could then also be phantom types.
> Tanner Nelson
> Vapor
> +1 (435) 773-2831
>
>> On Feb 7, 2017, at 10:32 PM, Michael Ilseman <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>>
>>> On Feb 7, 2017, at 1:21 PM, Tanner Nelson <[email protected]
>>> <mailto:[email protected]>> wrote:
>>>
>>> That's awesome. It looks like `(planned) Open and closed enums` is exactly
>>> what I'm looking for.
>>>
>>> Would it help if I created a concrete proposal for that or is it something
>>> the Swift team already has brewing?
>>>
>>
>> Note that open enums also have to solve ABI stability across versions.
>>
>> Basically, it sounds like you have an enum for which there is a reasonable
>> default handling in client code for any cases added in future versions of
>> your framework. Note that this is not true of all enums. The current
>> behavior of breaking clients when new cases are added forces them to think
>> about this new variant and their assumptions associated therein. This is
>> very desirable for many enums, even public ones.
>>
>> An intermediary approach could be to come up with an attribute to convey
>> your intent ala
>> https://github.com/apple/swift-evolution/blob/master/proposals/0047-nonvoid-warn.md
>>
>> <https://github.com/apple/swift-evolution/blob/master/proposals/0047-nonvoid-warn.md>.
>> The idea is to keep default behavior the same, but have something like
>> (straw man syntax) @defaultCaseRequired.
>>
>>
>>> Sent from my iPhone
>>>
>>> On Feb 7, 2017, at 22:01, Michael Ilseman <[email protected]
>>> <mailto:[email protected]>> wrote:
>>>
>>>> BTW, this will likely be part of the eventual design of “open”/resilient
>>>> enums ala
>>>> https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums
>>>> <https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums>.
>>>> There, the goal is to reduce both ABI and source breakage caused by this
>>>> sort of thing. It seems like for your purposes, you’re less inclined to
>>>> care about ABI breakage than source breakage, though that may change in
>>>> the future.
>>>>
>>>>
>>>>
>>>>> On Feb 7, 2017, at 7:12 AM, Tanner Nelson via swift-evolution
>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>
>>>>> Hello Swift Evolution,
>>>>>
>>>>> I'd like to propose that a warning be emitted when default cases are
>>>>> omitted for enums from other modules.
>>>>>
>>>>> What this would look like:
>>>>>
>>>>> OtherModule:
>>>>> ```
>>>>> public enum SomeEnum {
>>>>> case one
>>>>> case two
>>>>> }
>>>>>
>>>>> public let global: SomeEnum = .one
>>>>> ```
>>>>>
>>>>> executable:
>>>>> ```
>>>>> import OtherModule
>>>>>
>>>>> switch OtherModule.global {
>>>>> case .one: break
>>>>> case .two: break
>>>>> ^~~~~ ⚠︎ Warning: Default case recommended for imported enums.
>>>>> Fix-it: Add `default: break`
>>>>> }
>>>>> ```
>>>>>
>>>>> Why:
>>>>>
>>>>> Allowing the omission of a default case in an exhaustive switch makes the
>>>>> addition of a new case to the enum a breaking change.
>>>>> In other words, if you're exhaustively switching on an enum from an
>>>>> imported library, the imported library can break your code by adding a
>>>>> new case to that enum (which the library authors may erroneously view as
>>>>> an additive/minor-bump change).
>>>>>
>>>>> Background:
>>>>>
>>>>> As a maintainer of a Swift framework, public enums have been a pain point
>>>>> in maintaining semver. They've made it difficult to implement additive
>>>>> features and have necessitated the avoidance of enums in our future
>>>>> public API plans.
>>>>>
>>>>> Related Twitter thread:
>>>>> https://twitter.com/tanner0101/status/796860273760104454
>>>>> <https://twitter.com/tanner0101/status/796860273760104454>
>>>>>
>>>>> Looking forward to hearing your thoughts.
>>>>>
>>>>> Best,
>>>>> Tanner
>>>>>
>>>>> Tanner Nelson
>>>>> Vapor
>>>>> +1 (435) 773-2831
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> [email protected] <mailto:[email protected]>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>
>>
>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution