> On Feb 7, 2017, at 1:45 PM, Robert Widmann via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> I lean +1, but this answer on its own seems incomplete.  Exhaustiveness is an 
> important property, and it’s not clear what happens here now when you fall 
> through a “complete” case tree without matching a pattern, and in that sense 
> this plan solves a problem.  But it also would hinder a “future-you” from 
> going back and dealing with the ramifications of swapping a dependency for a 
> newer version, in that with a default now covering the rest of the cases the 
> compiler is unable to tell you which cases you are actually missing 
> post-upgrade.
> 
> Library Evolution 
> <https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst> 
> includes what I think is the more complete response here: An @closed 
> attribute for enums where a switch is guaranteed to be exhaustive.  (Though, 
> after the open discussion, I wonder if that keyword can’t be reused in some 
> way to provide the inverse restriction instead).

I agree that we probably need to allow both and the question is whether we have 
a default or not, and if we do, which one is the default.  

Personally, if we have a default I would prefer for the default to be closed.  
One of the most important attributes of enums is the fact that they encompass a 
fixed set of known cases.  I *want* my code to break if a new case is added to 
an enum of another module I depend on.  As the Library Evolution document notes 
"adding new cases should not be done lightly. Any clients attempting to do an 
exhaustive switch over all enum cases will likely not handle new cases well.”.  
Perhaps if a module author is not willing to commit to a fixed set of cases 
maybe publicly exposing an enum’s cases is not the best way to model the API in 
question.

I understand that making closed the default is the is slightly contrary to the 
principle that a module author explicitly opts-in to public API contracts.  
With that in mind, I would also consider it acceptable to decide that there 
should be *no* default, as we did in the `open` discussion.

It’s also worth noting that in the context of enums there are two ways in which 
an enum might be considered open - open to future extension by the module 
itself and open to extension by other modules.  The latter most closely matches 
the meaning of the `open` access modifier as it is currently used and I believe 
it has been requested on the list once or twice.  With that in mind, I don’t 
think we should reuse the `open` keyword to mean “open to extension in a future 
version of the module, but not open to extension by users of the module”.  That 
is basically equivalent to the meaning of `public` for classes.

This leads me to conclude that maybe the right answer here is to require 
library authors to specify `closed` *or* `public` when exposing an enum outside 
the module.  This follows the principle of library authors explicitly opting in 
to public API contracts, but also does not penalize the library author with 
additional verbosity for the contract which is more likely to lead to correct 
client code.


> 
>> On Feb 7, 2017, at 10:12 AM, Tanner Nelson via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to