Re: [swift-evolution] Enums and Source Compatibility

2017-12-28 Thread Wallacy via swift-evolution
Actually this make much more sense than original proposal.

Good call!

Just to check...

Its not better this?

public enum HomeworkExcuse {
  case eatenByPet
  default case thoughtItWasDueNextWeek}


If i understood correctly, if the enum is not exhaustible, must be
considered as this default value after a new case be introduced in a new
version of the lib right?

And for this one:

public enum HomeworkExcuse {
  case eatenByPet
  case thoughtItWasDueNextWeek
  fallback unknown // any word of course right?}


In this case fallback is the same as default right? But has as explicit new
label/case?

So, this is not enough?

public enum HomeworkExcuse {
  case eatenByPet
  fallback case thoughtItWasDueNextWeek}


If the dev wants to do make a default/fallback just use them for a regular
case, if not, if he wants to make a totally different case for a fallback
just declare another one to be the default/fallback (like unknown).

I understood your idea correctly?

Em qui, 21 de dez de 2017 às 20:48, Andrew Bennett via swift-evolution <
swift-evolution@swift.org> escreveu:

> Can you go into more detail about why the core team didn't like this?
>
> public enum HomeworkExcuse {
>   case eatenByPet
>   case thoughtItWasDueNextWeek
>   default // NEW}
>
>
> To me this is very close to an ideal solution, it fixes ABI concerns, it
> has sensible defaults. If it was changed a little bit:
>
> public enum HomeworkExcuse {
>   case eatenByPet
>   case thoughtItWasDueNextWeek
>   fallback unknown // NEW}
>
>
> Then I believe you would be able to have an exhaustive switch like this:
>
> switch thing {
>   case eatenByPet: break
>   case thoughtItWasDueNextWeek: break
>   case unknown: break}
>
>
> Which would *still allow compile-time errors if new cases are introduced*,
> while providing a concise way to show something is not exhaustible.
>
> This would also *support existing enums with "unknown" equivalent cases*
> would be able to explicitly label those fields as fallback without needing
> to make large code changes.
>
> I see no reason why you shouldn't be able to use ".unknown", which *should
> still allow this to be testable*.
>
> Thanks,
> Andrew
>
> On Tue, Oct 3, 2017 at 8:10 AM, Jordan Rose via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>> I don't think I have anything to say on this topic that I haven't already
>> said:
>>
>> - Switching exhaustively over non-exhaustive enums is uncommon.
>> - It's more important for a library to build without errors when its
>> dependencies change than it is to get an error. (This doesn't apply to
>> warnings, though.)
>> - Untestable code is dangerous, so having a language feature inherently
>> for untestable code seems bad.
>>
>> None of that negates your points; it just affects the weighting of
>> whether or not 'future' or 'switch!' is worth it. However, I've added a
>> link to your email in the proposal proper so that the Core Team and wider
>> review audience have a chance to decide differently.
>>
>> Jordan
>>
>>
>> On Oct 2, 2017, at 08:25, Vladimir.S via swift-evolution <
>> swift-evolution@swift.org> wrote:
>>
>>
>> Sorry to bother, but I still can't understand how the proposed change
>> *without* a 'future' case in switch will change our life and what would be
>> our steps to support our code and to not make our code buggy.
>> If I misunderstand something - sorry, please point me on this and I hope
>> this also help some one like me to understand the subject better.
>>
>> For example. I use OAuth2 framework, built by Carthage. Did add the
>> OAuth2.framework to my project.
>>
>> Currently OAuth2 exports 'public enum OAuth2Error'. I do have a place in
>> my code where I switch on each case of such error instance to do my best
>> with error: generate detailed description for user, other additional steps
>> depending on error.
>>
>> Will/should author of OAuth2 make OAuth2Error 'exhaustive' ? No.
>> Will new cases be added to that enum in future: Most likely Yes.
>> Do I need to switch on each case in my code? Yes.
>> Can I currently rely on compiler to keep my error processing in sync with
>> error cases defined in framework? Yes.
>> Can new cases appear in *run-time* of my app: NO, framework in embedded.
>> Will I be able to rely on compiler after the proposed change? No?!
>> What should I do to keep my switch in sync with OAuth2Error cases after
>> each update of OAuth2 library(framework)? Manually check if new cases are
>> added?! Configure lint/other tools to help me with this?!
>>
>> What I, as a developer, as a consumer of framework, need - is a way to
>> exhaustively switch on *some* external non-exhaustive enums *at the moment
>> of compilation*. And we can accomplish this only(AFAICT) with 'future' case
>> in 'switch'.
>> In case we'll have 'future' case my life will not be *worse* for this
>> project : I'll add it to my switch and still can receive help from compiler
>> to keep switch exhaustive.
>>
>> I don't support the opinion that we can't 

Re: [swift-evolution] Enums and Source Compatibility

2017-12-27 Thread Thorsten Seitz via swift-evolution


> Am 21.12.2017 um 23:48 schrieb Andrew Bennett via swift-evolution 
> :
> 
> Can you go into more detail about why the core team didn't like this?
> public enum HomeworkExcuse {
>   case eatenByPet
>   case thoughtItWasDueNextWeek
>   default // NEW
> }
> 
> To me this is very close to an ideal solution, it fixes ABI concerns, it has 
> sensible defaults. If it was changed a little bit:
> 
> public enum HomeworkExcuse {
>   case eatenByPet
>   case thoughtItWasDueNextWeek
>   fallback unknown // NEW
> }
> 
> Then I believe you would be able to have an exhaustive switch like this:
> 
> switch thing {
>   case eatenByPet: break
>   case thoughtItWasDueNextWeek: break
>   case unknown: break
> }
> 
> Which would still allow compile-time errors if new cases are introduced, 
> while providing a concise way to show something is not exhaustible.
> 
> This would also support existing enums with "unknown" equivalent cases would 
> be able to explicitly label those fields as fallback without needing to make 
> large code changes.
> 
> I see no reason why you shouldn't be able to use ".unknown", which should 
> still allow this to be testable.

This is an extremely elegant solution which seems to solve all problems very 
nicely!!
Yes, instead of marking the enum as non-exhaustive let’s just add a placeholder 
case for future cases.
I’m very much in favor of this.

-Thorsten



> 
> Thanks,
> Andrew
> 
> On Tue, Oct 3, 2017 at 8:10 AM, Jordan Rose via swift-evolution 
> > wrote:
> I don't think I have anything to say on this topic that I haven't already 
> said:
> 
> - Switching exhaustively over non-exhaustive enums is uncommon.
> - It's more important for a library to build without errors when its 
> dependencies change than it is to get an error. (This doesn't apply to 
> warnings, though.)
> - Untestable code is dangerous, so having a language feature inherently for 
> untestable code seems bad.
> 
> None of that negates your points; it just affects the weighting of whether or 
> not 'future' or 'switch!' is worth it. However, I've added a link to your 
> email in the proposal proper so that the Core Team and wider review audience 
> have a chance to decide differently.
> 
> Jordan
> 
> 
>> On Oct 2, 2017, at 08:25, Vladimir.S via swift-evolution 
>> > wrote:
>> 
>> 
>> Sorry to bother, but I still can't understand how the proposed change 
>> *without* a 'future' case in switch will change our life and what would be 
>> our steps to support our code and to not make our code buggy.
>> If I misunderstand something - sorry, please point me on this and I hope 
>> this also help some one like me to understand the subject better.
>> 
>> For example. I use OAuth2 framework, built by Carthage. Did add the 
>> OAuth2.framework to my project.
>> 
>> Currently OAuth2 exports 'public enum OAuth2Error'. I do have a place in my 
>> code where I switch on each case of such error instance to do my best with 
>> error: generate detailed description for user, other additional steps 
>> depending on error.
>> 
>> Will/should author of OAuth2 make OAuth2Error 'exhaustive' ? No.
>> Will new cases be added to that enum in future: Most likely Yes.
>> Do I need to switch on each case in my code? Yes.
>> Can I currently rely on compiler to keep my error processing in sync with 
>> error cases defined in framework? Yes.
>> Can new cases appear in *run-time* of my app: NO, framework in embedded.
>> Will I be able to rely on compiler after the proposed change? No?!
>> What should I do to keep my switch in sync with OAuth2Error cases after each 
>> update of OAuth2 library(framework)? Manually check if new cases are added?! 
>> Configure lint/other tools to help me with this?!
>> 
>> What I, as a developer, as a consumer of framework, need - is a way to 
>> exhaustively switch on *some* external non-exhaustive enums *at the moment 
>> of compilation*. And we can accomplish this only(AFAICT) with 'future' case 
>> in 'switch'.
>> In case we'll have 'future' case my life will not be *worse* for this 
>> project : I'll add it to my switch and still can receive help from compiler 
>> to keep switch exhaustive.
>> 
>> I don't support the opinion that we can't introduce 'future' case because of 
>> we can't test it:
>> 
>> 1. Not being able to keep my switch exhaustive when I need this, and so not 
>> being able to provide users of my app with best experience - IMO is worse.
>> 2. In my particular example, 'future' case will be *never* called, if I 
>> understand correctly.
>> 3. If switch on non-exhaustive enum is exhaustive by fact, we can't test the 
>> 'default' branch also. So, 'future' is in same position here with 'default'
>> 4. I believe if we'll decide we need 'future' case - we can suggest a way to 
>> call code in that case during the test process.
>> 
>> Seems like for embedded 

Re: [swift-evolution] Enums and Source Compatibility

2017-12-21 Thread Kevin Nattinger via swift-evolution

> On Oct 2, 2017, at 2:10 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> I don't think I have anything to say on this topic that I haven't already 
> said:
> 
> - Switching exhaustively over non-exhaustive enums is uncommon.

[Citation Needed]
As I pointed out in my email in the review thread, there are a significant 
number of enums in Apple's own frameworks that are commonly switched over 
exhaustively.

Additionally, uncommon or not, when this does come up, it's an enormous issue. 
Big enough that "it's uncommon" isn't sufficient justification for ignoring it.

> - It's more important for a library to build without errors when its 
> dependencies change than it is to get an error. (This doesn't apply to 
> warnings, though.)

Not sure I agree with this. In fact I think if anything it's more important for 
libraries than clients. Especially in the case of a new enum value it should 
support but doesn't.

> - Untestable code is dangerous, so having a language feature inherently for 
> untestable code seems bad.

A `default` case in the same situation is just as untestable, as you even point 
out in the proposal. Why do you keep using this as an argument against `future` 
but not `default`?

> 
> None of that negates your points; it just affects the weighting of whether or 
> not 'future' or 'switch!' is worth it. However, I've added a link to your 
> email in the proposal proper so that the Core Team and wider review audience 
> have a chance to decide differently.
> 
> Jordan
> 
> 
>> On Oct 2, 2017, at 08:25, Vladimir.S via swift-evolution 
>> > wrote:
>> 
>> 
>> Sorry to bother, but I still can't understand how the proposed change 
>> *without* a 'future' case in switch will change our life and what would be 
>> our steps to support our code and to not make our code buggy.
>> If I misunderstand something - sorry, please point me on this and I hope 
>> this also help some one like me to understand the subject better.
>> 
>> For example. I use OAuth2 framework, built by Carthage. Did add the 
>> OAuth2.framework to my project.
>> 
>> Currently OAuth2 exports 'public enum OAuth2Error'. I do have a place in my 
>> code where I switch on each case of such error instance to do my best with 
>> error: generate detailed description for user, other additional steps 
>> depending on error.
>> 
>> Will/should author of OAuth2 make OAuth2Error 'exhaustive' ? No.
>> Will new cases be added to that enum in future: Most likely Yes.
>> Do I need to switch on each case in my code? Yes.
>> Can I currently rely on compiler to keep my error processing in sync with 
>> error cases defined in framework? Yes.
>> Can new cases appear in *run-time* of my app: NO, framework in embedded.
>> Will I be able to rely on compiler after the proposed change? No?!
>> What should I do to keep my switch in sync with OAuth2Error cases after each 
>> update of OAuth2 library(framework)? Manually check if new cases are added?! 
>> Configure lint/other tools to help me with this?!
>> 
>> What I, as a developer, as a consumer of framework, need - is a way to 
>> exhaustively switch on *some* external non-exhaustive enums *at the moment 
>> of compilation*. And we can accomplish this only(AFAICT) with 'future' case 
>> in 'switch'.
>> In case we'll have 'future' case my life will not be *worse* for this 
>> project : I'll add it to my switch and still can receive help from compiler 
>> to keep switch exhaustive.
>> 
>> I don't support the opinion that we can't introduce 'future' case because of 
>> we can't test it:
>> 
>> 1. Not being able to keep my switch exhaustive when I need this, and so not 
>> being able to provide users of my app with best experience - IMO is worse.
>> 2. In my particular example, 'future' case will be *never* called, if I 
>> understand correctly.
>> 3. If switch on non-exhaustive enum is exhaustive by fact, we can't test the 
>> 'default' branch also. So, 'future' is in same position here with 'default'
>> 4. I believe if we'll decide we need 'future' case - we can suggest a way to 
>> call code in that case during the test process.
>> 
>> Seems like for embedded frameworks we should apply the same rules(regarding 
>> enums) as for sources, as we compile the app with concrete binary of 
>> framework and there just can't be new cases in enums. No?
>> 
>> Thank you for your time.
>> Vladimir.
>> 
>> On 01.10.2017 3:00, Slava Pestov via swift-evolution wrote:
 On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution 
  
 >> 
 wrote:
 
 I don’t see how it’s impractical. Quite a lot about how the library should 
 be optimally compiled and used depends on what you plan to do with it. If 
 it’s going to be installed somewhere private and you can guarantee clients 
 

Re: [swift-evolution] Enums and Source Compatibility

2017-12-21 Thread Andrew Bennett via swift-evolution
Can you go into more detail about why the core team didn't like this?

public enum HomeworkExcuse {
  case eatenByPet
  case thoughtItWasDueNextWeek
  default // NEW}


To me this is very close to an ideal solution, it fixes ABI concerns, it
has sensible defaults. If it was changed a little bit:

public enum HomeworkExcuse {
  case eatenByPet
  case thoughtItWasDueNextWeek
  fallback unknown // NEW}


Then I believe you would be able to have an exhaustive switch like this:

switch thing {
  case eatenByPet: break
  case thoughtItWasDueNextWeek: break
  case unknown: break}


Which would *still allow compile-time errors if new cases are introduced*,
while providing a concise way to show something is not exhaustible.

This would also *support existing enums with "unknown" equivalent cases*
would be able to explicitly label those fields as fallback without needing
to make large code changes.

I see no reason why you shouldn't be able to use ".unknown", which *should
still allow this to be testable*.

Thanks,
Andrew

On Tue, Oct 3, 2017 at 8:10 AM, Jordan Rose via swift-evolution <
swift-evolution@swift.org> wrote:

> I don't think I have anything to say on this topic that I haven't already
> said:
>
> - Switching exhaustively over non-exhaustive enums is uncommon.
> - It's more important for a library to build without errors when its
> dependencies change than it is to get an error. (This doesn't apply to
> warnings, though.)
> - Untestable code is dangerous, so having a language feature inherently
> for untestable code seems bad.
>
> None of that negates your points; it just affects the weighting of whether
> or not 'future' or 'switch!' is worth it. However, I've added a link to
> your email in the proposal proper so that the Core Team and wider review
> audience have a chance to decide differently.
>
> Jordan
>
>
> On Oct 2, 2017, at 08:25, Vladimir.S via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>
> Sorry to bother, but I still can't understand how the proposed change
> *without* a 'future' case in switch will change our life and what would be
> our steps to support our code and to not make our code buggy.
> If I misunderstand something - sorry, please point me on this and I hope
> this also help some one like me to understand the subject better.
>
> For example. I use OAuth2 framework, built by Carthage. Did add the
> OAuth2.framework to my project.
>
> Currently OAuth2 exports 'public enum OAuth2Error'. I do have a place in
> my code where I switch on each case of such error instance to do my best
> with error: generate detailed description for user, other additional steps
> depending on error.
>
> Will/should author of OAuth2 make OAuth2Error 'exhaustive' ? No.
> Will new cases be added to that enum in future: Most likely Yes.
> Do I need to switch on each case in my code? Yes.
> Can I currently rely on compiler to keep my error processing in sync with
> error cases defined in framework? Yes.
> Can new cases appear in *run-time* of my app: NO, framework in embedded.
> Will I be able to rely on compiler after the proposed change? No?!
> What should I do to keep my switch in sync with OAuth2Error cases after
> each update of OAuth2 library(framework)? Manually check if new cases are
> added?! Configure lint/other tools to help me with this?!
>
> What I, as a developer, as a consumer of framework, need - is a way to
> exhaustively switch on *some* external non-exhaustive enums *at the moment
> of compilation*. And we can accomplish this only(AFAICT) with 'future' case
> in 'switch'.
> In case we'll have 'future' case my life will not be *worse* for this
> project : I'll add it to my switch and still can receive help from compiler
> to keep switch exhaustive.
>
> I don't support the opinion that we can't introduce 'future' case because
> of we can't test it:
>
> 1. Not being able to keep my switch exhaustive when I need this, and so
> not being able to provide users of my app with best experience - IMO is
> worse.
> 2. In my particular example, 'future' case will be *never* called, if I
> understand correctly.
> 3. If switch on non-exhaustive enum is exhaustive by fact, we can't test
> the 'default' branch also. So, 'future' is in same position here with
> 'default'
> 4. I believe if we'll decide we need 'future' case - we can suggest a way
> to call code in that case during the test process.
>
> Seems like for embedded frameworks we should apply the same
> rules(regarding enums) as for sources, as we compile the app with concrete
> binary of framework and there just can't be new cases in enums. No?
>
> Thank you for your time.
> Vladimir.
>
> On 01.10.2017 3:00, Slava Pestov via swift-evolution wrote:
>
> On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution <
> swift-evolution@swift.org  >> wrote:
>
> I don’t see how it’s impractical. Quite a lot about how the library should
> be optimally compiled and used depends on 

Re: [swift-evolution] Enums and Source Compatibility

2017-10-02 Thread Jordan Rose via swift-evolution
I don't think I have anything to say on this topic that I haven't already said:

- Switching exhaustively over non-exhaustive enums is uncommon.
- It's more important for a library to build without errors when its 
dependencies change than it is to get an error. (This doesn't apply to 
warnings, though.)
- Untestable code is dangerous, so having a language feature inherently for 
untestable code seems bad.

None of that negates your points; it just affects the weighting of whether or 
not 'future' or 'switch!' is worth it. However, I've added a link to your email 
in the proposal proper so that the Core Team and wider review audience have a 
chance to decide differently.

Jordan


> On Oct 2, 2017, at 08:25, Vladimir.S via swift-evolution 
>  wrote:
> 
> 
> Sorry to bother, but I still can't understand how the proposed change 
> *without* a 'future' case in switch will change our life and what would be 
> our steps to support our code and to not make our code buggy.
> If I misunderstand something - sorry, please point me on this and I hope this 
> also help some one like me to understand the subject better.
> 
> For example. I use OAuth2 framework, built by Carthage. Did add the 
> OAuth2.framework to my project.
> 
> Currently OAuth2 exports 'public enum OAuth2Error'. I do have a place in my 
> code where I switch on each case of such error instance to do my best with 
> error: generate detailed description for user, other additional steps 
> depending on error.
> 
> Will/should author of OAuth2 make OAuth2Error 'exhaustive' ? No.
> Will new cases be added to that enum in future: Most likely Yes.
> Do I need to switch on each case in my code? Yes.
> Can I currently rely on compiler to keep my error processing in sync with 
> error cases defined in framework? Yes.
> Can new cases appear in *run-time* of my app: NO, framework in embedded.
> Will I be able to rely on compiler after the proposed change? No?!
> What should I do to keep my switch in sync with OAuth2Error cases after each 
> update of OAuth2 library(framework)? Manually check if new cases are added?! 
> Configure lint/other tools to help me with this?!
> 
> What I, as a developer, as a consumer of framework, need - is a way to 
> exhaustively switch on *some* external non-exhaustive enums *at the moment of 
> compilation*. And we can accomplish this only(AFAICT) with 'future' case in 
> 'switch'.
> In case we'll have 'future' case my life will not be *worse* for this project 
> : I'll add it to my switch and still can receive help from compiler to keep 
> switch exhaustive.
> 
> I don't support the opinion that we can't introduce 'future' case because of 
> we can't test it:
> 
> 1. Not being able to keep my switch exhaustive when I need this, and so not 
> being able to provide users of my app with best experience - IMO is worse.
> 2. In my particular example, 'future' case will be *never* called, if I 
> understand correctly.
> 3. If switch on non-exhaustive enum is exhaustive by fact, we can't test the 
> 'default' branch also. So, 'future' is in same position here with 'default'
> 4. I believe if we'll decide we need 'future' case - we can suggest a way to 
> call code in that case during the test process.
> 
> Seems like for embedded frameworks we should apply the same rules(regarding 
> enums) as for sources, as we compile the app with concrete binary of 
> framework and there just can't be new cases in enums. No?
> 
> Thank you for your time.
> Vladimir.
> 
> On 01.10.2017 3:00, Slava Pestov via swift-evolution wrote:
>>> On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution 
>>> > wrote:
>>> 
>>> I don’t see how it’s impractical. Quite a lot about how the library should 
>>> be optimally compiled and used depends on what you plan to do with it. If 
>>> it’s going to be installed somewhere private and you can guarantee clients 
>>> will always have the latest version, you can assume all data types are 
>>> final, @_fixed_layout, @exhaustive, whatever (essentially in-module). An 
>>> example of that would be a library embedded inside an iOS app bundle. If 
>>> it’s going to be installed somewhere public and expose some API (like 
>>> Apple’s frameworks), then you’re going to have to think about binary 
>>> compatibility.
>>> 
>>> That also means that in-app libraries are optimised as much as they can be, 
>>> and that resilience-related changes on the declaration side can be limited 
>>> to the limited set of Swift developers who truly have to care about that.
>> We do plan on exposing an -enable-resilience flag which basically does what 
>> you describe. When a library is built without -enable-resilience, all types 
>> are assumed to be fixed layout, etc. However, we don’t want language flags 
>> to change language semantics, so exhaustive/nonexhaustive still make sense 
>> even when building without resilience, I think. When you switch over a 

Re: [swift-evolution] Enums and Source Compatibility

2017-10-02 Thread Jordan Rose via swift-evolution
This exists, but it's imperfect: it's possible that an app and its embedded 
frameworks are not all linked against the same version of the SDK, and then the 
system framework has to go with whatever the app does. (It's more important to 
behave consistently within a process.)

It's not impossible to design something like this for Swift and even for 
third-party frameworks, but that particular limitation is inherent. It also 
doesn't always make sense to try to emulate the old behavior—in the first 
system that gains support for DVDs, it's not really worth pretending that 
they're CDs or floppy disks.  I contend that non-exhaustive enums are a fact of 
life for OS frameworks, and still a good thing for open source frameworks.

Jordan


> On Oct 2, 2017, at 10:29, Wallacy via swift-evolution 
>  wrote:
> 
> @Slava
> 
> If my understanding is correct. If I compile my application with the x.y.z 
> version of a Apple System Framework (like Cocoa). And this framework is 
> updated, several calls from my application to the "new" framework version 
> x.z.a behave like in the x.y.z version for compatibility issues right? I see 
> this being mentioned in the Cocoa documentations sometimes.
> 
> Is possible to do this here?
> 
> I usually don't care about non-exhaustive enums. We avoid this even in 
> languages which do not enforce us (using external tools sometimes). But i can 
> understand the "need" in some projects.
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-10-02 Thread Dave DeLong via swift-evolution


> On Oct 2, 2017, at 11:29 AM, Wallacy via swift-evolution 
>  wrote:
> 
> @Slava
> 
> If my understanding is correct. If I compile my application with the x.y.z 
> version of a Apple System Framework (like Cocoa). And this framework is 
> updated, several calls from my application to the "new" framework version 
> x.z.a behave like in the x.y.z version for compatibility issues right? I see 
> this being mentioned in the Cocoa documentations sometimes.
> 
> Is possible to do this here?

Unfortunately, no. That behavior is manually implemented by the framework 
authors.

Dave

> 
> I usually don't care about non-exhaustive enums. We avoid this even in 
> languages which do not enforce us (using external tools sometimes). But i can 
> understand the "need" in some projects.
> 
> 
> Em sáb, 30 de set de 2017 às 21:00, Slava Pestov via swift-evolution 
> > escreveu:
>> On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution 
>> > wrote:
>> 
>> I don’t see how it’s impractical. Quite a lot about how the library should 
>> be optimally compiled and used depends on what you plan to do with it. If 
>> it’s going to be installed somewhere private and you can guarantee clients 
>> will always have the latest version, you can assume all data types are 
>> final, @_fixed_layout, @exhaustive, whatever (essentially in-module). An 
>> example of that would be a library embedded inside an iOS app bundle. If 
>> it’s going to be installed somewhere public and expose some API (like 
>> Apple’s frameworks), then you’re going to have to think about binary 
>> compatibility.
>> 
>> That also means that in-app libraries are optimised as much as they can be, 
>> and that resilience-related changes on the declaration side can be limited 
>> to the limited set of Swift developers who truly have to care about that.
> 
> We do plan on exposing an -enable-resilience flag which basically does what 
> you describe. When a library is built without -enable-resilience, all types 
> are assumed to be fixed layout, etc. However, we don’t want language flags to 
> change language semantics, so exhaustive/nonexhaustive still make sense even 
> when building without resilience, I think. When you switch over a 
> non-exhaustive enum that came from a library built without 
> -enable-resilience, the compiler can still use the most efficient possible 
> access pattern and assume that no new cases will be introduced, but the type 
> checker would still require a default case to be present. The optimizer can 
> then basically strip out the default case as dead code.
> 
> Slava
> 
>> 
>> - Karl
> 
> ___
> 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

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


Re: [swift-evolution] Enums and Source Compatibility

2017-10-02 Thread Wallacy via swift-evolution
@Slava

If my understanding is correct. If I compile my application with the x.y.z
version of a Apple System Framework (like Cocoa). And this framework is
updated, several calls from my application to the "new" framework version
x.z.a behave like in the x.y.z version for compatibility issues right? I
see this being mentioned in the Cocoa documentations sometimes.

Is possible to do this here?

I usually don't care about non-exhaustive enums. We avoid this even in
languages which do not enforce us (using external tools sometimes). But i
can understand the "need" in some projects.


Em sáb, 30 de set de 2017 às 21:00, Slava Pestov via swift-evolution <
swift-evolution@swift.org> escreveu:

> On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> I don’t see how it’s impractical. Quite a lot about how the library should
> be optimally compiled and used depends on what you plan to do with it. If
> it’s going to be installed somewhere private and you can guarantee clients
> will always have the latest version, you can assume all data types are
> final, @_fixed_layout, @exhaustive, whatever (essentially in-module). An
> example of that would be a library embedded inside an iOS app bundle. If
> it’s going to be installed somewhere public and expose some API (like
> Apple’s frameworks), then you’re going to have to think about binary
> compatibility.
>
> That also means that in-app libraries are optimised as much as they can
> be, and that resilience-related changes on the declaration side can be
> limited to the limited set of Swift developers who truly have to care about
> that.
>
>
> We do plan on exposing an -enable-resilience flag which basically does
> what you describe. When a library is built without -enable-resilience, all
> types are assumed to be fixed layout, etc. However, we don’t want language
> flags to change language semantics, so exhaustive/nonexhaustive still make
> sense even when building without resilience, I think. When you switch over
> a non-exhaustive enum that came from a library built without
> -enable-resilience, the compiler can still use the most efficient possible
> access pattern and assume that no new cases will be introduced, but the
> type checker would still require a default case to be present. The
> optimizer can then basically strip out the default case as dead code.
>
> Slava
>
>
> - Karl
>
>
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-10-02 Thread Charlie Monroe via swift-evolution
+1 for everything Vladimir says - which is why I'm pushing for switch! (just 
like try!, etc.) which would preserve current behavior.

> On Oct 2, 2017, at 5:25 PM, Vladimir.S via swift-evolution 
>  wrote:
> 
> 
> Sorry to bother, but I still can't understand how the proposed change 
> *without* a 'future' case in switch will change our life and what would be 
> our steps to support our code and to not make our code buggy.
> If I misunderstand something - sorry, please point me on this and I hope this 
> also help some one like me to understand the subject better.
> 
> For example. I use OAuth2 framework, built by Carthage. Did add the 
> OAuth2.framework to my project.
> 
> Currently OAuth2 exports 'public enum OAuth2Error'. I do have a place in my 
> code where I switch on each case of such error instance to do my best with 
> error: generate detailed description for user, other additional steps 
> depending on error.
> 
> Will/should author of OAuth2 make OAuth2Error 'exhaustive' ? No.
> Will new cases be added to that enum in future: Most likely Yes.
> Do I need to switch on each case in my code? Yes.
> Can I currently rely on compiler to keep my error processing in sync with 
> error cases defined in framework? Yes.
> Can new cases appear in *run-time* of my app: NO, framework in embedded.
> Will I be able to rely on compiler after the proposed change? No?!
> What should I do to keep my switch in sync with OAuth2Error cases after each 
> update of OAuth2 library(framework)? Manually check if new cases are added?! 
> Configure lint/other tools to help me with this?!
> 
> What I, as a developer, as a consumer of framework, need - is a way to 
> exhaustively switch on *some* external non-exhaustive enums *at the moment of 
> compilation*. And we can accomplish this only(AFAICT) with 'future' case in 
> 'switch'.
> In case we'll have 'future' case my life will not be *worse* for this project 
> : I'll add it to my switch and still can receive help from compiler to keep 
> switch exhaustive.
> 
> I don't support the opinion that we can't introduce 'future' case because of 
> we can't test it:
> 
> 1. Not being able to keep my switch exhaustive when I need this, and so not 
> being able to provide users of my app with best experience - IMO is worse.
> 2. In my particular example, 'future' case will be *never* called, if I 
> understand correctly.
> 3. If switch on non-exhaustive enum is exhaustive by fact, we can't test the 
> 'default' branch also. So, 'future' is in same position here with 'default'
> 4. I believe if we'll decide we need 'future' case - we can suggest a way to 
> call code in that case during the test process.
> 
> Seems like for embedded frameworks we should apply the same rules(regarding 
> enums) as for sources, as we compile the app with concrete binary of 
> framework and there just can't be new cases in enums. No?
> 
> Thank you for your time.
> Vladimir.
> 
> On 01.10.2017 3:00, Slava Pestov via swift-evolution wrote:
>>> On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution 
>>> > wrote:
>>> 
>>> I don’t see how it’s impractical. Quite a lot about how the library should 
>>> be optimally compiled and used depends on what you plan to do with it. If 
>>> it’s going to be installed somewhere private and you can guarantee clients 
>>> will always have the latest version, you can assume all data types are 
>>> final, @_fixed_layout, @exhaustive, whatever (essentially in-module). An 
>>> example of that would be a library embedded inside an iOS app bundle. If 
>>> it’s going to be installed somewhere public and expose some API (like 
>>> Apple’s frameworks), then you’re going to have to think about binary 
>>> compatibility.
>>> 
>>> That also means that in-app libraries are optimised as much as they can be, 
>>> and that resilience-related changes on the declaration side can be limited 
>>> to the limited set of Swift developers who truly have to care about that.
>> We do plan on exposing an -enable-resilience flag which basically does what 
>> you describe. When a library is built without -enable-resilience, all types 
>> are assumed to be fixed layout, etc. However, we don’t want language flags 
>> to change language semantics, so exhaustive/nonexhaustive still make sense 
>> even when building without resilience, I think. When you switch over a 
>> non-exhaustive enum that came from a library built without 
>> -enable-resilience, the compiler can still use the most efficient possible 
>> access pattern and assume that no new cases will be introduced, but the type 
>> checker would still require a default case to be present. The optimizer can 
>> then basically strip out the default case as dead code.
>> Slava
>>> 
>>> - Karl
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> 

Re: [swift-evolution] Enums and Source Compatibility

2017-10-02 Thread Vladimir.S via swift-evolution


Sorry to bother, but I still can't understand how the proposed change *without* a 
'future' case in switch will change our life and what would be our steps to support 
our code and to not make our code buggy.
If I misunderstand something - sorry, please point me on this and I hope this also 
help some one like me to understand the subject better.


For example. I use OAuth2 framework, built by Carthage. Did add the OAuth2.framework 
to my project.


Currently OAuth2 exports 'public enum OAuth2Error'. I do have a place in my code 
where I switch on each case of such error instance to do my best with error: generate 
detailed description for user, other additional steps depending on error.


Will/should author of OAuth2 make OAuth2Error 'exhaustive' ? No.
Will new cases be added to that enum in future: Most likely Yes.
Do I need to switch on each case in my code? Yes.
Can I currently rely on compiler to keep my error processing in sync with error cases 
defined in framework? Yes.

Can new cases appear in *run-time* of my app: NO, framework in embedded.
Will I be able to rely on compiler after the proposed change? No?!
What should I do to keep my switch in sync with OAuth2Error cases after each update 
of OAuth2 library(framework)? Manually check if new cases are added?! Configure 
lint/other tools to help me with this?!


What I, as a developer, as a consumer of framework, need - is a way to exhaustively 
switch on *some* external non-exhaustive enums *at the moment of compilation*. And we 
can accomplish this only(AFAICT) with 'future' case in 'switch'.
In case we'll have 'future' case my life will not be *worse* for this project : I'll 
add it to my switch and still can receive help from compiler to keep switch exhaustive.


I don't support the opinion that we can't introduce 'future' case because of we can't 
test it:


1. Not being able to keep my switch exhaustive when I need this, and so not being 
able to provide users of my app with best experience - IMO is worse.
2. In my particular example, 'future' case will be *never* called, if I understand 
correctly.
3. If switch on non-exhaustive enum is exhaustive by fact, we can't test the 
'default' branch also. So, 'future' is in same position here with 'default'
4. I believe if we'll decide we need 'future' case - we can suggest a way to call 
code in that case during the test process.


Seems like for embedded frameworks we should apply the same rules(regarding enums) as 
for sources, as we compile the app with concrete binary of framework and there just 
can't be new cases in enums. No?


Thank you for your time.
Vladimir.

On 01.10.2017 3:00, Slava Pestov via swift-evolution wrote:


On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution 
> wrote:


I don’t see how it’s impractical. Quite a lot about how the library should be 
optimally compiled and used depends on what you plan to do with it. If it’s going 
to be installed somewhere private and you can guarantee clients will always have 
the latest version, you can assume all data types are final, @_fixed_layout, 
@exhaustive, whatever (essentially in-module). An example of that would be a 
library embedded inside an iOS app bundle. If it’s going to be installed somewhere 
public and expose some API (like Apple’s frameworks), then you’re going to have to 
think about binary compatibility.


That also means that in-app libraries are optimised as much as they can be, and 
that resilience-related changes on the declaration side can be limited to the 
limited set of Swift developers who truly have to care about that.


We do plan on exposing an -enable-resilience flag which basically does what you 
describe. When a library is built without -enable-resilience, all types are assumed 
to be fixed layout, etc. However, we don’t want language flags to change language 
semantics, so exhaustive/nonexhaustive still make sense even when building without 
resilience, I think. When you switch over a non-exhaustive enum that came from a 
library built without -enable-resilience, the compiler can still use the most 
efficient possible access pattern and assume that no new cases will be introduced, 
but the type checker would still require a default case to be present. The optimizer 
can then basically strip out the default case as dead code.


Slava



- Karl




___
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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-30 Thread Slava Pestov via swift-evolution

> On Sep 30, 2017, at 4:46 PM, Karl Wagner via swift-evolution 
>  wrote:
> 
> I don’t see how it’s impractical. Quite a lot about how the library should be 
> optimally compiled and used depends on what you plan to do with it. If it’s 
> going to be installed somewhere private and you can guarantee clients will 
> always have the latest version, you can assume all data types are final, 
> @_fixed_layout, @exhaustive, whatever (essentially in-module). An example of 
> that would be a library embedded inside an iOS app bundle. If it’s going to 
> be installed somewhere public and expose some API (like Apple’s frameworks), 
> then you’re going to have to think about binary compatibility.
> 
> That also means that in-app libraries are optimised as much as they can be, 
> and that resilience-related changes on the declaration side can be limited to 
> the limited set of Swift developers who truly have to care about that.

We do plan on exposing an -enable-resilience flag which basically does what you 
describe. When a library is built without -enable-resilience, all types are 
assumed to be fixed layout, etc. However, we don’t want language flags to 
change language semantics, so exhaustive/nonexhaustive still make sense even 
when building without resilience, I think. When you switch over a 
non-exhaustive enum that came from a library built without -enable-resilience, 
the compiler can still use the most efficient possible access pattern and 
assume that no new cases will be introduced, but the type checker would still 
require a default case to be present. The optimizer can then basically strip 
out the default case as dead code.

Slava

> 
> - Karl

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-30 Thread Karl Wagner via swift-evolution


> On 29. Sep 2017, at 00:24, Dave DeLong via swift-evolution 
>  wrote:
> 
> I also realize that this may be an impractical approach to solving this 
> problem, because it would require teaching the analyzer about built products, 
> with knowledge of what’s going to be copied, etc etc.
> 
> So, the alternative view to this would be:
> 
> - any enum that you are compiling is exhaustive
> - everything else is non-exhaustive
> 
> Dave
> 

I don’t see how it’s impractical. Quite a lot about how the library should be 
optimally compiled and used depends on what you plan to do with it. If it’s 
going to be installed somewhere private and you can guarantee clients will 
always have the latest version, you can assume all data types are final, 
@_fixed_layout, @exhaustive, whatever (essentially in-module). An example of 
that would be a library embedded inside an iOS app bundle. If it’s going to be 
installed somewhere public and expose some API (like Apple’s frameworks), then 
you’re going to have to think about binary compatibility.

That also means that in-app libraries are optimised as much as they can be, and 
that resilience-related changes on the declaration side can be limited to the 
limited set of Swift developers who truly have to care about that.

- Karl

>> On Sep 28, 2017, at 4:18 PM, Dave DeLong via swift-evolution 
>> > wrote:
>> 
>> I don’t think this use-case should be overlooked, especially as we approach 
>> the stable ABI.
>> 
>> If a library can change out from underneath you (because you’re not 
>> embedding it yourself) then it is inherently unsafe to assume that any enum 
>> in that library is exhaustive. The developer may think that it is for 
>> version 1, but the development of version 2 may reveal cases that were not 
>> originally considered. Apple, which has just about as much experience as 
>> anyone in the world with shipping frameworks, has a strong commitment to 
>> binary compatibility, but even they get it wrong sometimes.
>> 
>> IMO, the proper way to deal with “exhaustive” enums vs not is:
>> 
>> - any enum in any framework you ship is exhaustive. (Rationale: since you’re 
>> embedding it with your product, you have explicit control over handling all 
>> its cases)
>> 
>> - any enum in any framework you link is non-exhaustive. (Rationale: since 
>> the framework is not part of your product, it could change without you 
>> knowing, which means you must handle unexpected values via a default case)
>> 
>> Dave
>> 
>>> On Sep 21, 2017, at 12:48 PM, Jordan Rose >> > wrote:
>>> 
>>> 
 On Sep 20, 2017, at 16:15, Dave DeLong > wrote:
 
 Hi Jordan,
 
 One thing I’m still not clear on exhaustive vs non-exhaustive…
 
 What will stop a developer from releasing an exhaustive enum in version 1 
 of their library, and then adding a new case in version 2?
 
 With ABI stability and libraries getting updated independently of apps, 
 this can be a major problem.
>>> 
>>> We have some ideas to deal with this, though nothing promised yet:
>>> 
>>> - A checker that can compare APIs across library versions, using 
>>> swiftmodule files or similar.
>>> - Encoding the layout of a type in a symbol name. We could have clients 
>>> link against this symbol so that they’d fail to launch if it changes, or 
>>> just check the list of exported symbols to make sure it didn’t change.
>>> 
>>> The feature’s useful even if we have to do it by hand for now, but it’s a 
>>> good question to ask. I’ll mention this in the proposal under “Future 
>>> directions”.
>>> 
>>> Jordan
>> 
>> ___
>> 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

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-29 Thread Jordan Rose via swift-evolution
(responses to both Jon and Goffredo's most recent point inline)

> On Sep 28, 2017, at 16:15, Goffredo Marocchi  wrote:
> 
> Agreed, I am not seeing this change doing so much good because maybe it could 
> prevent issues Library writers or developers updating libraries without 
> checking things... not trying to be rude and/or non empathetic, but 
> exhaustive enums never struck me as a bad thing and the reasons why they 
> could be bad very quickly leads one to think “maybe you should not have been 
> switching on enums there...”.

I suspect this is correct! Which makes non-exhaustive enums a way to 
communicate that this is probably not a good enum to switch exhaustively on. 
(Since switch statements can be used for other pattern-matching purposes in 
Swift, taking the F# route of disallowing matching cases altogether seems 
unnecessary.)

> On 28 Sep 2017, at 23:57, Jon Shier via swift-evolution 
> > wrote:
> 
>>  Actually, since proper dependency management for Apple platforms has 
>> existed outside of Apple for years now, this likely wouldn’t affect me at 
>> all, as long as the libraries I was using properly followed semantic 
>> versioning. I could keep using the compatible version of the libraries for 
>> however long I needed before moving to the new version and updating my code 
>> to exhaustively check for the new values. So please don’t make this change 
>> thinking you’ll be helping non-Apple framework providers here. Aside from 
>> actual binary compatibility I’m not sure there’s a compatibility case to be 
>> made here. 

>From the semantic versioning point of view, non-exhaustive enums allow you to 
>add a new case while changing only the minor version number and not the major 
>version number. That is certainly an extra feature for non-Apple framework 
>providers; whether or not it's a sufficiently useful one to justify the 
>increased language complexity is, well, part of your evaluation of the 
>proposal.

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread David Sweeris via swift-evolution

> On Sep 28, 2017, at 4:15 PM, Goffredo Marocchi via swift-evolution 
>  wrote:
> 
> Agreed, I am not seeing this change doing so much good because maybe it could 
> prevent issues Library writers or developers updating libraries without 
> checking things... not trying to be rude and/or non empathetic, but 
> exhaustive enums never struck me as a bad thing and the reasons why they 
> could be bad very quickly leads one to think “maybe you should not have been 
> switching on enums there...”.

You're suggesting that we use enums when something is known to be exhaustive, 
and then something like this when it's not?

struct SomeOptionSetOrWhatever : Equatable, RawRepresentable {
public static func == (lhs: SomeOptionSetOrWhatever, rhs: 
SomeOptionSetOrWhatever) -> Bool { return lhs.value == rhs.value  }
public static let optionOne = SomeOptionSetOrWhatever(privateInit: 1)
public static let optionTwo = SomeOptionSetOrWhatever(privateInit: 2)
private let value: Int
private init(privateInit value: Int) { self.value = value }
public init?(rawValue: Int) {
switch rawValue {
case 1: self = .optionOne
case 2: self = .optionTwo
case _: value = 0; return nil
}
}
public var rawValue: Int { return value }
}

func foo(x: SomeOptionSetOrWhatever) {
switch x {
case .optionOne: print("first option")
case .optionTwo: print("second option")
default: break //without this line, it's a "switch much be exhaustive" 
error
}
}

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread Goffredo Marocchi via swift-evolution
Agreed, I am not seeing this change doing so much good because maybe it could 
prevent issues Library writers or developers updating libraries without 
checking things... not trying to be rude and/or non empathetic, but exhaustive 
enums never struck me as a bad thing and the reasons why they could be bad very 
quickly leads one to think “maybe you should not have been switching on enums 
there...”.


Sent from my iPhone

> On 28 Sep 2017, at 23:57, Jon Shier via swift-evolution 
>  wrote:
> 
>   Actually, since proper dependency management for Apple platforms has 
> existed outside of Apple for years now, this likely wouldn’t affect me at 
> all, as long as the libraries I was using properly followed semantic 
> versioning. I could keep using the compatible version of the libraries for 
> however long I needed before moving to the new version and updating my code 
> to exhaustively check for the new values. So please don’t make this change 
> thinking you’ll be helping non-Apple framework providers here. Aside from 
> actual binary compatibility I’m not sure there’s a compatibility case to be 
> made here. 
> 
> 
> 
> Jon
> 
>> On Sep 28, 2017, at 4:52 PM, Jordan Rose via swift-evolution 
>>  wrote:
>> 
>> 
>> 
>>> On Sep 27, 2017, at 16:48, Jessie Serrino  wrote:
>>> 
>>> Hi there,
>>> 
>>> Just want to circle back on a few things.
>>> 
>>> You mentioned that library vendors communicate deprecation notices, but 
>>> this is very prone to error. If someone misses the notice that a library 
>>> puts out to communicate that the contracts of the enum have changed, this 
>>> could break existing functionality they have already built. 
>>> 
>>> You also mention that it's really hard for a library developer to predict 
>>> how their enum will change, but it's even harder for a library developer to 
>>> fully predict how a different user will use their library. As a developer, 
>>> I don't want to have to look at the release notes to find out when a 
>>> library has changed its contracts-- I want it to alert me in the most 
>>> aggressive way possible to make sure that major changes to the library have 
>>> been captured in my own code.
>> 
>> Hi, Jessie. This is a reasonable view, but in our experience it's not the 
>> most important thing. What we've seen is that people want their code to keep 
>> building after an update, and in particular they want their dependencies to 
>> keep building. That is, if your app depends on HomeworkKit, and HomeworkKit 
>> adds a new case, you probably want to know about it. But if someone's app 
>> depends on CoreAcademia, and CoreAcademia depends on HomeworkKit, they're 
>> probably just going to be upset if CoreAcademia no longer builds. In 
>> practice, that person/team stops updating HomeworkKit until there's a 
>> CoreAcademia update available, or possibly stops working on their app 
>> altogether, to avoid editing someone else's library.
>> 
>> (Again, this becomes even more critical if HomeworkKit is a part of the OS, 
>> in which case there's not even a choice whether or not to update. But I can 
>> see that being handled separately.)
>> 
>> I'm not completely against having an additional notion of an 
>> "otherwise-exhaustive" switch, as discussed under "Preserve exhaustiveness 
>> diagnostics for non-exhaustive enums". But that's a feature we can add 
>> later, whereas differentiating exhaustive and non-exhaustive enums is 
>> something that must be done before Swift libraries can be part of the OS.
>> 
>> Jordan
>> ___
>> 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
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread Jon Shier via swift-evolution
Actually, since proper dependency management for Apple platforms has 
existed outside of Apple for years now, this likely wouldn’t affect me at all, 
as long as the libraries I was using properly followed semantic versioning. I 
could keep using the compatible version of the libraries for however long I 
needed before moving to the new version and updating my code to exhaustively 
check for the new values. So please don’t make this change thinking you’ll be 
helping non-Apple framework providers here. Aside from actual binary 
compatibility I’m not sure there’s a compatibility case to be made here. 



Jon

> On Sep 28, 2017, at 4:52 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> 
> 
>> On Sep 27, 2017, at 16:48, Jessie Serrino > > wrote:
>> 
>> Hi there,
>> 
>> Just want to circle back on a few things.
>> 
>> You mentioned that library vendors communicate deprecation notices, but this 
>> is very prone to error. If someone misses the notice that a library puts out 
>> to communicate that the contracts of the enum have changed, this could break 
>> existing functionality they have already built. 
>> 
>> You also mention that it's really hard for a library developer to predict 
>> how their enum will change, but it's even harder for a library developer to 
>> fully predict how a different user will use their library. As a developer, I 
>> don't want to have to look at the release notes to find out when a library 
>> has changed its contracts-- I want it to alert me in the most aggressive way 
>> possible to make sure that major changes to the library have been captured 
>> in my own code.
> 
> Hi, Jessie. This is a reasonable view, but in our experience it's not the 
> most important thing. What we've seen is that people want their code to keep 
> building after an update, and in particular they want their dependencies to 
> keep building. That is, if your app depends on HomeworkKit, and HomeworkKit 
> adds a new case, you probably want to know about it. But if someone's app 
> depends on CoreAcademia, and CoreAcademia depends on HomeworkKit, they're 
> probably just going to be upset if CoreAcademia no longer builds. In 
> practice, that person/team stops updating HomeworkKit until there's a 
> CoreAcademia update available, or possibly stops working on their app 
> altogether, to avoid editing someone else's library.
> 
> (Again, this becomes even more critical if HomeworkKit is a part of the OS, 
> in which case there's not even a choice whether or not to update. But I can 
> see that being handled separately.)
> 
> I'm not completely against having an additional notion of an 
> "otherwise-exhaustive" switch, as discussed under "Preserve exhaustiveness 
> diagnostics for non-exhaustive enums". But that's a feature we can add later, 
> whereas differentiating exhaustive and non-exhaustive enums is something that 
> must be done before Swift libraries can be part of the OS.
> 
> Jordan
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread Dave DeLong via swift-evolution
I also realize that this may be an impractical approach to solving this 
problem, because it would require teaching the analyzer about built products, 
with knowledge of what’s going to be copied, etc etc.

So, the alternative view to this would be:

- any enum that you are compiling is exhaustive
- everything else is non-exhaustive

Dave

> On Sep 28, 2017, at 4:18 PM, Dave DeLong via swift-evolution 
>  wrote:
> 
> I don’t think this use-case should be overlooked, especially as we approach 
> the stable ABI.
> 
> If a library can change out from underneath you (because you’re not embedding 
> it yourself) then it is inherently unsafe to assume that any enum in that 
> library is exhaustive. The developer may think that it is for version 1, but 
> the development of version 2 may reveal cases that were not originally 
> considered. Apple, which has just about as much experience as anyone in the 
> world with shipping frameworks, has a strong commitment to binary 
> compatibility, but even they get it wrong sometimes.
> 
> IMO, the proper way to deal with “exhaustive” enums vs not is:
> 
> - any enum in any framework you ship is exhaustive. (Rationale: since you’re 
> embedding it with your product, you have explicit control over handling all 
> its cases)
> 
> - any enum in any framework you link is non-exhaustive. (Rationale: since the 
> framework is not part of your product, it could change without you knowing, 
> which means you must handle unexpected values via a default case)
> 
> Dave
> 
>> On Sep 21, 2017, at 12:48 PM, Jordan Rose > > wrote:
>> 
>> 
>>> On Sep 20, 2017, at 16:15, Dave DeLong >> > wrote:
>>> 
>>> Hi Jordan,
>>> 
>>> One thing I’m still not clear on exhaustive vs non-exhaustive…
>>> 
>>> What will stop a developer from releasing an exhaustive enum in version 1 
>>> of their library, and then adding a new case in version 2?
>>> 
>>> With ABI stability and libraries getting updated independently of apps, 
>>> this can be a major problem.
>> 
>> We have some ideas to deal with this, though nothing promised yet:
>> 
>> - A checker that can compare APIs across library versions, using swiftmodule 
>> files or similar.
>> - Encoding the layout of a type in a symbol name. We could have clients link 
>> against this symbol so that they’d fail to launch if it changes, or just 
>> check the list of exported symbols to make sure it didn’t change.
>> 
>> The feature’s useful even if we have to do it by hand for now, but it’s a 
>> good question to ask. I’ll mention this in the proposal under “Future 
>> directions”.
>> 
>> Jordan
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread Dave DeLong via swift-evolution
I don’t think this use-case should be overlooked, especially as we approach the 
stable ABI.

If a library can change out from underneath you (because you’re not embedding 
it yourself) then it is inherently unsafe to assume that any enum in that 
library is exhaustive. The developer may think that it is for version 1, but 
the development of version 2 may reveal cases that were not originally 
considered. Apple, which has just about as much experience as anyone in the 
world with shipping frameworks, has a strong commitment to binary 
compatibility, but even they get it wrong sometimes.

IMO, the proper way to deal with “exhaustive” enums vs not is:

- any enum in any framework you ship is exhaustive. (Rationale: since you’re 
embedding it with your product, you have explicit control over handling all its 
cases)

- any enum in any framework you link is non-exhaustive. (Rationale: since the 
framework is not part of your product, it could change without you knowing, 
which means you must handle unexpected values via a default case)

Dave

> On Sep 21, 2017, at 12:48 PM, Jordan Rose  wrote:
> 
> 
>> On Sep 20, 2017, at 16:15, Dave DeLong  wrote:
>> 
>> Hi Jordan,
>> 
>> One thing I’m still not clear on exhaustive vs non-exhaustive…
>> 
>> What will stop a developer from releasing an exhaustive enum in version 1 of 
>> their library, and then adding a new case in version 2?
>> 
>> With ABI stability and libraries getting updated independently of apps, this 
>> can be a major problem.
> 
> We have some ideas to deal with this, though nothing promised yet:
> 
> - A checker that can compare APIs across library versions, using swiftmodule 
> files or similar.
> - Encoding the layout of a type in a symbol name. We could have clients link 
> against this symbol so that they’d fail to launch if it changes, or just 
> check the list of exported symbols to make sure it didn’t change.
> 
> The feature’s useful even if we have to do it by hand for now, but it’s a 
> good question to ask. I’ll mention this in the proposal under “Future 
> directions”.
> 
> Jordan

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread Jordan Rose via swift-evolution


> On Sep 22, 2017, at 08:20, Karl Wagner  wrote:
> 
> So I’m in favour of the change, but absolutely not in favour of the keywords. 
> We need to standardise a minimal set of keywords which broadly cover the 
> things library authors need to care about (versioning, sub-typing, inlining, 
> etc). How is “exhaustive” different from “final” or “@_versioned”? How do 
> they interact? I think we could come up with a more coherent message.

As I've mentioned before, unifying all these things is not a good idea because 
they affect clients in different ways. That is, clients need to know about some 
of these and not others, and library authors probably shouldn't be considering 
them all to be equivalent.

- Exhaustivity, of course, affects diagnostics around 'switch' statements.

- The unformalized struct attribute currently spelled '@_fixedLayout' is an 
optimization hint that only matters for binary frameworks*; any struct in a 
library you build from source can have its layout guaranteed to clients.

- The unformalized function attribute currently spelled '@_inlinable' ought to 
be in the same bucket as '@_fixedLayout', but in practice I'm not sure we'll be 
able to make everything inlinable and still support fast compilation (yes, yes, 
go ahead and laugh). This might remain a user-specified attribute for a while, 
in the same way that you have to manually decide to make certain operations 
into `static inline` functions in C-based languages.

- The unformalized attribute currently spelled '@_versioned' is basically 
"public but hidden", in that it makes a declaration part of your ABI without 
making it part of your API. This is related to the other attributes, but I 
don't think it's the same thing. It's also mostly unrelated to what the Library 
Evolution document calls "versioning"; it's standing in for a proper 
availability annotation on a declaration that's 'internal' rather than 'public'.

I could see the latter three being related, but I think there's a definite 
reason to keep exhaustivity separate. It's more similar to existing modifiers 
like 'open' than to ABI- and optimization-related annotations like 
'@_fixedLayout'; it's just too bad that 'open' has the reverse connotations 
from what we need.


That said, I'd actually be fine with `final`. Like exhaustivity, `final` allows 
clients outside the original library to do things they otherwise wouldn't be 
able to: add 'required' initializers. (It also has effects within the module, 
which exhaustivity doesn't, but that seems okay to me.)

Jordan


* I'm using "binary frameworks" to mean "libraries with binary compatibility 
requirements" again; a pre-built library that's embedded with an app doesn't 
run into these issues.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread Jordan Rose via swift-evolution


> On Sep 22, 2017, at 17:50, Rex Fenley  wrote:
> 
> It’s really only an issue for people whose frameworks are used across 
> variously-distributed apps (your own, or other peoples’). The typical dynamic 
> library use-case. Those people already know to be careful, so why make 
> non-exhaustive the default for everybody? It’s a fair point.
>  
> Getting this right can be pretty hard. For example, I expect that 
> @_inlineable functions within the enum’s declaring module will also be 
> affected by this (a client could inline the code, then you add an enum 
> case…). At the same time, it’s difficult for a shared library vendor to say 
> definitively that a particular enum will never change (unless it really is a 
> very simple thing, like NSComparisonResult) - almost anything with meaning to 
> how the library works is usually subject to change in case edge-cases are 
> discovered. The analysis of Apple’s frameworks is good data to prove it, but 
> it also makes sense that vendors like to retain as much implementation 
> freedom as possible.
> 
> Just for clarity, this seems like the binary compatibility piece correct? As 
> far as I understand this could only affect a dynamically linked library, but 
> if you're linking a library dynamically, how could you inline a function, 
> since if it's dynamically linked you don't know what to inline?

Karl answered this part already, but this is equivalent to `static inline` 
functions in C. The library is dynamically linked, but specific pieces of it 
are available for clients to inline.


> Also, I've never heard of these kinds of issues in other languages with 
> exhaustive pattern matching. Would be very interested to know how OCaml or 
> Haskell solve this problem?

This is a great question, and I feel a little ashamed that I didn't include a 
proper cross-language study ahead of time!

As far as I can tell, Haskell and OCaml completely punt on this issue. All 
"enums" are exhaustive (the existing Swift behavior), and adding a new "case" 
to a "public enum" is a source-breaking change all the time. (Neither Haskell 
nor OCaml seems to care much about binary compatibility.) This is definitely a 
sign that you can have a successful language without a form of non-exhaustive 
enums other than "protocols". However, I think that just means that people 
never add new cases to existing enums, which is not where we want to end up 
with Swift. Kotlin also falls in this bucket.

Scala's notion of enums is "sealed traits", which is something like a protocol 
that can only be conformed to from a particular file. The compiler then checks 
for all the possible types and allows you to exhaustively switch over them. In 
some sense that means Scala is matching our behavior, in that they're 
"non-exhaustive by default, exhaustive via 'sealed'", but doing that with 
protocols isn't really equivalent because in the non-sealed case someone could 
conform to the protocol from outside the "module".

Rust has an accepted proposal to add non-exhaustive enums 
 
that looks a lot like this one, but where "exhaustive" is still the default to 
not break existing Rust programs. (There are some interesting differences that 
come up in Rust but not Swift; in particular they need a notion of 
non-exhaustive structs because their structs can be decomposed in 
pattern-matching as well.)

There's a C++ proposal about an [[exhaustive]] attribute 
 that roughly 
matches this use case, although of course in C "falling off the end of a 
switch" is perfectly legal. The proposed attribute would merely be a hint to 
compilers for what warnings to emit.

Enums in D are like enums in C, but D distinguishes `switch` from `final 
switch`, and only the latter is exhaustive. (That is, it's a client-side 
decision.)

F# unions either expose all of their "cases" or none of them 
. 
I guess the Swift equivalent of this would be not allowing you to switch on 
such an enum at all, as if it were a struct with private fields.

The C# docs have a nice section on how the language isn't very helpful 

 for non-exhaustive enums. Objective-C, of course, is in the same bucket, 
though we (Apple) could start doing things with the 'enum_extensibility' 
attribute we just added.

---

I'm not sure this'll change anyone's mind, but it was still a good exercise. 
I'll add this to the proposal as well, so people don't have to dig through the 
thread to find this information.

Jordan

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread Jordan Rose via swift-evolution


> On Sep 27, 2017, at 16:48, Jessie Serrino  wrote:
> 
> Hi there,
> 
> Just want to circle back on a few things.
> 
> You mentioned that library vendors communicate deprecation notices, but this 
> is very prone to error. If someone misses the notice that a library puts out 
> to communicate that the contracts of the enum have changed, this could break 
> existing functionality they have already built. 
> 
> You also mention that it's really hard for a library developer to predict how 
> their enum will change, but it's even harder for a library developer to fully 
> predict how a different user will use their library. As a developer, I don't 
> want to have to look at the release notes to find out when a library has 
> changed its contracts-- I want it to alert me in the most aggressive way 
> possible to make sure that major changes to the library have been captured in 
> my own code.

Hi, Jessie. This is a reasonable view, but in our experience it's not the most 
important thing. What we've seen is that people want their code to keep 
building after an update, and in particular they want their dependencies to 
keep building. That is, if your app depends on HomeworkKit, and HomeworkKit 
adds a new case, you probably want to know about it. But if someone's app 
depends on CoreAcademia, and CoreAcademia depends on HomeworkKit, they're 
probably just going to be upset if CoreAcademia no longer builds. In practice, 
that person/team stops updating HomeworkKit until there's a CoreAcademia update 
available, or possibly stops working on their app altogether, to avoid editing 
someone else's library.

(Again, this becomes even more critical if HomeworkKit is a part of the OS, in 
which case there's not even a choice whether or not to update. But I can see 
that being handled separately.)

I'm not completely against having an additional notion of an 
"otherwise-exhaustive" switch, as discussed under "Preserve exhaustiveness 
diagnostics for non-exhaustive enums". But that's a feature we can add later, 
whereas differentiating exhaustive and non-exhaustive enums is something that 
must be done before Swift libraries can be part of the OS.

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-28 Thread Jessie Serrino via swift-evolution
Hi there,

Just want to circle back on a few things.

You mentioned that library vendors communicate deprecation notices, but
this is very prone to error. If someone misses the notice that a library
puts out to communicate that the contracts of the enum have changed, this
could break existing functionality they have already built.

You also mention that it's really hard for a library developer to predict
how their enum will change, but it's even harder for a library developer to
fully predict how a different user will use their library. As a developer,
I don't want to have to look at the release notes to find out when a
library has changed its contracts-- I want it to alert me in the most
aggressive way possible to make sure that major changes to the library have
been captured in my own code.

Jessie

On 21. Sep 2017, at 00:51, Rex Fenley via swift-evolution <
swift-evolution@swift.org> wrote:

Hi Jordan,

I've been keeping up with most of the discussion since I last emailed about
my concern about making nonexhaustive the default mode for enums. So far I
am still strongly in the camp of exhaustive by default.

Most of my understanding comes from the perspective of source
compatibility; since I'm primarily an iOS app developer and contributor to
open source through CocoaPods, I don't have enough experience with binary
compatibility issues to understand the breadth of the effects of such a
change on binary compatibility - so I will argue from the perspective of
source compatibility. Additionally, all the following applies exclusively
to enums from Swift and not Obj-C/C. Largely my concerns stem from the "default
effect "-
whatever default is chosen is going to unconsciously bias developers to use
that default.

To start, I don't follow how nonexhaustive by default leads to more secure
code or promises less. In a world where nonexhaustive is default,
hard-to-track bugs will be introduced frequently into many Swift
developer's code.

   - Evolving contracts - The change you suggest leaves it up to the user
   to remember to add new cases into their code if an enum ever does change in
   a framework, and their code relies on exhaustive pattern matching.

I think this is the right thing to do. Library vendors can still
communicate changes with clients through deprecation notices. Ultimately it
is up to the vendor to maintain compatibility for people switching against
those older cases, and up to the clients to adopt any new behaviour that
gets implemented.


   - Unhandled case bugs - This will lead to inconsistencies and
   hard-to-track bugs, since it would require the user to then track down an
   unhandled case that they may not even be aware exists (forcing googling,
   searching through documentation, etc.).

This is something that I certainly have experienced in the past working
across teams programming in Obj-C, and Swift has so far completely
eliminated this class of bugs! In a world where exhaustive remains default,
nothing changes, fewer bugs.


I’m not sure that those issues are so difficult to track down. You’ll know
that switch statements which fall-through to a default case are suspicious
- but they already are today, too!. It’s not really any different to having
allowing singular “if”s without a corresponding “else”. I could also see
the debugging value in a “future” case label, but it’s not necessary IMO.

Although, I can kind of see your point:

If you’re talking about a private framework (e.g. the multi-module App
scenario), then things are a little different for you because typically,
you’ll ship new versions of the framework and App together. The framework
can be as fragile as you like in that case - you can break all the ABI
stability rules, because there will no apps importing the new version of
the framework who were compiled against older versions of it. In many ways,
those frameworks are really like static libraries (with extras, like
resources).

It’s really only an issue for people whose frameworks are used across
variously-distributed apps (your own, or other peoples’). The typical
dynamic library use-case. Those people already know to be careful, so why
make non-exhaustive the default for everybody? It’s a fair point.

Getting this right can be pretty hard. For example, I expect that
@_inlineable functions within the enum’s declaring module will also be
affected by this (a client could inline the code, then you add an enum
case…). At the same time, it’s difficult for a shared library vendor to say
definitively that a particular enum will never change (unless it really is
a very simple thing, like NSComparisonResult) - almost anything with
meaning to how the library works is usually subject to change in case
edge-cases are discovered. The analysis of Apple’s frameworks is good data
to prove it, but it also makes sense that vendors like to retain as much
implementation freedom as possible.

So I’m in favour of the change, 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-23 Thread Karl Wagner via swift-evolution
  
  

  
  
  
Yes, it’s binary compatiblity (ABI).
  

  
And yes, you’re right that inlineable code is especially fragile to changes 
made in later versions of the library.
  

  
See:   
https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#inlineable-code
  
  
>   
> On Sep 23, 2017 at 2:50 am,   (mailto:swift-evolution@swift.org)>  wrote:
>   
>   
>   
>   
> > It’s really only an issue for people whose frameworks are used across 
> > variously-distributed apps (your own, or other peoples’). The typical 
> > dynamic library use-case. Those people already know to be careful, so why 
> > make non-exhaustive the default for everybody? It’s a fair point.
>   
>   
>   
> > Getting this right can be pretty hard. For example, I expect that 
> > @_inlineable functions within the enum’s declaring module will also be 
> > affected by this (a client could inline the code, then you add an enum 
> > case…). At the same time, it’s difficult for a shared library vendor to say 
> > definitively that a particular enum will never change (unless it really is 
> > a very simple thing, like NSComparisonResult) - almost anything with 
> > meaning to how the library works is usually subject to change in case 
> > edge-cases are discovered. The analysis of Apple’s frameworks is good data 
> > to prove it, but it also makes sense that vendors like to retain as much 
> > implementation freedom as possible.
>   
>
>   
> Just for clarity, this seems like the binary compatibility piece correct? As 
> far as I understand this could only affect a dynamically linked library, but 
> if you're linking a library dynamically, how could you inline a function, 
> since if it's dynamically linked you don't know what to inline?
>   
>
>   
> Also, I've never heard of these kinds of issues in other languages with 
> exhaustive pattern matching. Would be very interested to know how OCaml or 
> Haskell solve this problem?
>   
>
>   
> Thanks for your input
>   
>   
>   
>   
>
>   
> On Fri, Sep 22, 2017 at 8:20 AM, Karl Wagner   (mailto:razie...@gmail.com)>  wrote:
>   
> >   
> >
> >   
> >   
> > >   
> > > On 21. Sep 2017, at 00:51, Rex Fenley via swift-evolution  
> > >   wrote:
> > >   
> > >   
> > >   
> > >   Hi Jordan,
> > >   
> > >  I've been keeping up with most of the discussion since I last emailed 
> > > about my concern about making nonexhaustive the default mode for enums. 
> > > So far I am still strongly in the camp of exhaustive by default.
> > >   
> > >  Most of my understanding comes from the perspective of source 
> > > compatibility; since I'm primarily an iOS app developer and contributor 
> > > to open source through CocoaPods, I don't have enough experience with 
> > > binary compatibility issues to understand the breadth of the effects of 
> > > such a change on binary compatibility - so I will argue from the 
> > > perspective of source compatibility. Additionally, all the following 
> > > applies exclusively to enums from Swift and not Obj-C/C. Largely my 
> > > concerns stem from the   "default effect 
> > > (https://en.m.wikipedia.org/wiki/Default_effect_(psychology))"- whatever 
> > > default is chosen is going to unconsciously bias developers to use that 
> > > default.
> > >   
> > >  To start, I don't follow how nonexhaustive by default leads to more 
> > > secure code or promises less. In a world where nonexhaustive is default, 
> > > hard-to-track bugs will be introduced frequently into many Swift 
> > > developer's code.   
> > >   
> > >   
> > > Evolving contracts - The change you suggest leaves it up to the user to 
> > > remember to add new cases into their code if an enum ever does change in 
> > > a framework, and their code relies on exhaustive pattern matching.   
> > >   
> > >   
> > >   
> > >   
> >   
> > I think this is the right thing to do. Library vendors can still 
> > communicate changes with clients through deprecation notices. Ultimately it 
> > is up to the vendor to maintain compatibility for people switching against 
> > those older cases, and up to the clients to adopt any new behaviour that 
> > gets implemented.
> > 
> >
> >   
> > >   
> > >   
> > > 
> > >   
> > > Unhandled case bugs - This will lead to inconsistencies and hard-to-track 
> > > bugs, since it would require the user to then track down an unhandled 
> > > case that they may not even be aware exists (forcing googling, searching 
> > > through documentation, etc.).
> > >   
> > >   This is something that I certainly have experienced in the past working 
> > > across teams programming in Obj-C, and Swift has so far completely 
> > > eliminated this class of bugs! In a world where exhaustive remains 
> > > default, nothing changes, fewer bugs.
> > >   
> >
> >   
> > I’m not sure that those issues are so difficult to track down. You’ll know 
> > that switch statements which fall-through to a 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-22 Thread Rex Fenley via swift-evolution
>
> It’s really only an issue for people whose frameworks are used across
> variously-distributed apps (your own, or other peoples’). The typical
> dynamic library use-case. Those people already know to be careful, so why
> make non-exhaustive the default for everybody? It’s a fair point.
>


> Getting this right can be pretty hard. For example, I expect that
> @_inlineable functions within the enum’s declaring module will also be
> affected by this (a client could inline the code, then you add an enum
> case…). At the same time, it’s difficult for a shared library vendor to say
> definitively that a particular enum will never change (unless it really is
> a very simple thing, like NSComparisonResult) - almost anything with
> meaning to how the library works is usually subject to change in case
> edge-cases are discovered. The analysis of Apple’s frameworks is good data
> to prove it, but it also makes sense that vendors like to retain as much
> implementation freedom as possible.


Just for clarity, this seems like the binary compatibility piece correct?
As far as I understand this could only affect a dynamically linked library,
but if you're linking a library dynamically, how could you inline a
function, since if it's dynamically linked you don't know what to inline?

Also, I've never heard of these kinds of issues in other languages with
exhaustive pattern matching. Would be very interested to know how OCaml or
Haskell solve this problem?

Thanks for your input


On Fri, Sep 22, 2017 at 8:20 AM, Karl Wagner  wrote:

>
> On 21. Sep 2017, at 00:51, Rex Fenley via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> Hi Jordan,
>
> I've been keeping up with most of the discussion since I last emailed
> about my concern about making nonexhaustive the default mode for enums. So
> far I am still strongly in the camp of exhaustive by default.
>
> Most of my understanding comes from the perspective of source
> compatibility; since I'm primarily an iOS app developer and contributor to
> open source through CocoaPods, I don't have enough experience with binary
> compatibility issues to understand the breadth of the effects of such a
> change on binary compatibility - so I will argue from the perspective of
> source compatibility. Additionally, all the following applies exclusively
> to enums from Swift and not Obj-C/C. Largely my concerns stem from the 
> "default
> effect "-
> whatever default is chosen is going to unconsciously bias developers to use
> that default.
>
> To start, I don't follow how nonexhaustive by default leads to more secure
> code or promises less. In a world where nonexhaustive is default,
> hard-to-track bugs will be introduced frequently into many Swift
> developer's code.
>
>- Evolving contracts - The change you suggest leaves it up to the user
>to remember to add new cases into their code if an enum ever does change in
>a framework, and their code relies on exhaustive pattern matching.
>
> I think this is the right thing to do. Library vendors can still
> communicate changes with clients through deprecation notices. Ultimately it
> is up to the vendor to maintain compatibility for people switching against
> those older cases, and up to the clients to adopt any new behaviour that
> gets implemented.
>
>
>- Unhandled case bugs - This will lead to inconsistencies and
>hard-to-track bugs, since it would require the user to then track down an
>unhandled case that they may not even be aware exists (forcing googling,
>searching through documentation, etc.).
>
> This is something that I certainly have experienced in the past working
> across teams programming in Obj-C, and Swift has so far completely
> eliminated this class of bugs! In a world where exhaustive remains default,
> nothing changes, fewer bugs.
>
>
> I’m not sure that those issues are so difficult to track down. You’ll know
> that switch statements which fall-through to a default case are suspicious
> - but they already are today, too!. It’s not really any different to having
> allowing singular “if”s without a corresponding “else”. I could also see
> the debugging value in a “future” case label, but it’s not necessary IMO.
>
> Although, I can kind of see your point:
>
> If you’re talking about a private framework (e.g. the multi-module App
> scenario), then things are a little different for you because typically,
> you’ll ship new versions of the framework and App together. The framework
> can be as fragile as you like in that case - you can break all the ABI
> stability rules, because there will no apps importing the new version of
> the framework who were compiled against older versions of it. In many ways,
> those frameworks are really like static libraries (with extras, like
> resources).
>
> It’s really only an issue for people whose frameworks are used across
> variously-distributed apps (your own, or other 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-22 Thread Karl Wagner via swift-evolution

> On 22. Sep 2017, at 17:21, Karl Wagner via swift-evolution 
>  wrote:
> 
>> 
>> On 21. Sep 2017, at 00:51, Rex Fenley via swift-evolution 
>> > wrote:
>> 
>> Hi Jordan,
>> 
>> I've been keeping up with most of the discussion since I last emailed about 
>> my concern about making nonexhaustive the default mode for enums. So far I 
>> am still strongly in the camp of exhaustive by default.
>> 
>> Most of my understanding comes from the perspective of source compatibility; 
>> since I'm primarily an iOS app developer and contributor to open source 
>> through CocoaPods, I don't have enough experience with binary compatibility 
>> issues to understand the breadth of the effects of such a change on binary 
>> compatibility - so I will argue from the perspective of source 
>> compatibility. Additionally, all the following applies exclusively to enums 
>> from Swift and not Obj-C/C. Largely my concerns stem from the "default 
>> effect "- 
>> whatever default is chosen is going to unconsciously bias developers to use 
>> that default.
>> 
>> To start, I don't follow how nonexhaustive by default leads to more secure 
>> code or promises less. In a world where nonexhaustive is default, 
>> hard-to-track bugs will be introduced frequently into many Swift developer's 
>> code. 
>> Evolving contracts - The change you suggest leaves it up to the user to 
>> remember to add new cases into their code if an enum ever does change in a 
>> framework, and their code relies on exhaustive pattern matching. 
> I think this is the right thing to do. Library vendors can still communicate 
> changes with clients through deprecation notices. Ultimately it is up to the 
> vendor to maintain compatibility for people switching against those older 
> cases, and up to the clients to adopt any new behaviour that gets implemented.
> 
>> Unhandled case bugs - This will lead to inconsistencies and hard-to-track 
>> bugs, since it would require the user to then track down an unhandled case 
>> that they may not even be aware exists (forcing googling, searching through 
>> documentation, etc.).
>> This is something that I certainly have experienced in the past working 
>> across teams programming in Obj-C, and Swift has so far completely 
>> eliminated this class of bugs! In a world where exhaustive remains default, 
>> nothing changes, fewer bugs.
> 
> I’m not sure that those issues are so difficult to track down. You’ll know 
> that switch statements which fall-through to a default case are suspicious - 
> but they already are today, too!. It’s not really any different to having 
> allowing singular “if”s without a corresponding “else”. I could also see the 
> debugging value in a “future” case label, but it’s not necessary IMO.
> 
> Although, I can kind of see your point:
> 
> If you’re talking about a private framework (e.g. the multi-module App 
> scenario), then things are a little different for you because typically, 
> you’ll ship new versions of the framework and App together. The framework can 
> be as fragile as you like in that case - you can break all the ABI stability 
> rules, because there will no apps importing the new version of the framework 
> who were compiled against older versions of it. In many ways, those 
> frameworks are really like static libraries (with extras, like resources).

Of course, you can’t actually use static libraries because on iOS, for example, 
you might have XPC services or other mini-applications which also want to use 
your model libraries. Static libraries would bloat your binary size.

Is there some kind of middle-ground, perhaps? Like a fragile dynamic library, 
which makes no attempt to be resilient?

- Karl

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-22 Thread Karl Wagner via swift-evolution

> On 21. Sep 2017, at 00:51, Rex Fenley via swift-evolution 
>  wrote:
> 
> Hi Jordan,
> 
> I've been keeping up with most of the discussion since I last emailed about 
> my concern about making nonexhaustive the default mode for enums. So far I am 
> still strongly in the camp of exhaustive by default.
> 
> Most of my understanding comes from the perspective of source compatibility; 
> since I'm primarily an iOS app developer and contributor to open source 
> through CocoaPods, I don't have enough experience with binary compatibility 
> issues to understand the breadth of the effects of such a change on binary 
> compatibility - so I will argue from the perspective of source compatibility. 
> Additionally, all the following applies exclusively to enums from Swift and 
> not Obj-C/C. Largely my concerns stem from the "default effect 
> "- whatever 
> default is chosen is going to unconsciously bias developers to use that 
> default.
> 
> To start, I don't follow how nonexhaustive by default leads to more secure 
> code or promises less. In a world where nonexhaustive is default, 
> hard-to-track bugs will be introduced frequently into many Swift developer's 
> code. 
> Evolving contracts - The change you suggest leaves it up to the user to 
> remember to add new cases into their code if an enum ever does change in a 
> framework, and their code relies on exhaustive pattern matching. 
I think this is the right thing to do. Library vendors can still communicate 
changes with clients through deprecation notices. Ultimately it is up to the 
vendor to maintain compatibility for people switching against those older 
cases, and up to the clients to adopt any new behaviour that gets implemented.

> Unhandled case bugs - This will lead to inconsistencies and hard-to-track 
> bugs, since it would require the user to then track down an unhandled case 
> that they may not even be aware exists (forcing googling, searching through 
> documentation, etc.).
> This is something that I certainly have experienced in the past working 
> across teams programming in Obj-C, and Swift has so far completely eliminated 
> this class of bugs! In a world where exhaustive remains default, nothing 
> changes, fewer bugs.

I’m not sure that those issues are so difficult to track down. You’ll know that 
switch statements which fall-through to a default case are suspicious - but 
they already are today, too!. It’s not really any different to having allowing 
singular “if”s without a corresponding “else”. I could also see the debugging 
value in a “future” case label, but it’s not necessary IMO.

Although, I can kind of see your point:

If you’re talking about a private framework (e.g. the multi-module App 
scenario), then things are a little different for you because typically, you’ll 
ship new versions of the framework and App together. The framework can be as 
fragile as you like in that case - you can break all the ABI stability rules, 
because there will no apps importing the new version of the framework who were 
compiled against older versions of it. In many ways, those frameworks are 
really like static libraries (with extras, like resources).

It’s really only an issue for people whose frameworks are used across 
variously-distributed apps (your own, or other peoples’). The typical dynamic 
library use-case. Those people already know to be careful, so why make 
non-exhaustive the default for everybody? It’s a fair point.

Getting this right can be pretty hard. For example, I expect that @_inlineable 
functions within the enum’s declaring module will also be affected by this (a 
client could inline the code, then you add an enum case…). At the same time, 
it’s difficult for a shared library vendor to say definitively that a 
particular enum will never change (unless it really is a very simple thing, 
like NSComparisonResult) - almost anything with meaning to how the library 
works is usually subject to change in case edge-cases are discovered. The 
analysis of Apple’s frameworks is good data to prove it, but it also makes 
sense that vendors like to retain as much implementation freedom as possible.

So I’m in favour of the change, but absolutely not in favour of the keywords. 
We need to standardise a minimal set of keywords which broadly cover the things 
library authors need to care about (versioning, sub-typing, inlining, etc). How 
is “exhaustive” different from “final” or “@_versioned”? How do they interact? 
I think we could come up with a more coherent message.

- Karl

> 
> Next off is developer usability. As someone who has contributed to several 
> frameworks in Swift, one thing I know is that you can always count on people 
> complaining about the usability of their library - it's something you learn 
> to expect. If it turns out that people are very frustrated with an enum 
> constantly changing and breaking compatibility, they 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-21 Thread Jordan Rose via swift-evolution

> On Sep 20, 2017, at 16:15, Dave DeLong  wrote:
> 
> Hi Jordan,
> 
> One thing I’m still not clear on exhaustive vs non-exhaustive…
> 
> What will stop a developer from releasing an exhaustive enum in version 1 of 
> their library, and then adding a new case in version 2?
> 
> With ABI stability and libraries getting updated independently of apps, this 
> can be a major problem.

We have some ideas to deal with this, though nothing promised yet:

- A checker that can compare APIs across library versions, using swiftmodule 
files or similar.
- Encoding the layout of a type in a symbol name. We could have clients link 
against this symbol so that they’d fail to launch if it changes, or just check 
the list of exported symbols to make sure it didn’t change.

The feature’s useful even if we have to do it by hand for now, but it’s a good 
question to ask. I’ll mention this in the proposal under “Future directions”.

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-20 Thread David Sweeris via swift-evolution

> On Sep 20, 2017, at 4:15 PM, Dave DeLong via swift-evolution 
>  wrote:
> 
> Hi Jordan,
> 
> One thing I’m still not clear on exhaustive vs non-exhaustive…
> 
> What will stop a developer from releasing an exhaustive enum in version 1 of 
> their library, and then adding a new case in version 2?

Nothing, other than it would break code written using version 1.

- Dave Sweeris
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-20 Thread Dave DeLong via swift-evolution
Hi Jordan,

One thing I’m still not clear on exhaustive vs non-exhaustive…

What will stop a developer from releasing an exhaustive enum in version 1 of 
their library, and then adding a new case in version 2?

With ABI stability and libraries getting updated independently of apps, this 
can be a major problem.

Dave


> On Sep 18, 2017, at 11:48 AM, Jordan Rose via swift-evolution 
>  wrote:
> 
> I don't think unit tests help much here. In the case where an 'exhaustive' 
> enum ought to be 'nonexhaustive', unit tests wouldn't help you catch the 
> issue until you tried adding a new case. And in both cases, a unit test would 
> only help if you tried to switch exhaustively over the enum, something you 
> may not think to write (depending on what the enum is, of course).
> 
> In either direction, there's a potential error of omission, and if you've 
> "omitted" the annotation from your library code I wouldn't assume you'd 
> remember to check that specific thing in a unit test.
> 
> Jordan
> 
> 
>> On Sep 16, 2017, at 00:44, Goffredo Marocchi > > wrote:
>> 
>> Sorry for being naive, but aside from open (and the decision not to make it 
>> the default which again hurts the users of the library),  wouldn’t the 
>> playground library example be ok if the framework author had validated it 
>> with unit tests?
>> 
>> Sent from my iPhone
>> 
>> On 16 Sep 2017, at 01:07, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>>> Hi, Rex. I definitely agree that 'exhaustive' is the right model for a 
>>> multi-module app; indeed, there's no real reason for a single project to do 
>>> anything else. However, it is not always the right behavior for libraries 
>>> that actually get distributed, whether as source or as binary. In this case 
>>> we want to minimize the error of omission: in the app case, forgetting 
>>> "exhaustive" is an annoyance that you notice and fix once across your code 
>>> base, but in the library case forgetting the "default case" means putting 
>>> out a source-breaking release, and for libraries that have binary 
>>> compatibility constraints there's no recourse at all.
>>> 
>>> While most of the proposal deals with the experience we've had with the 
>>> Apple SDKs (as written in Objective-C), we actually have run into this case 
>>> in Swift already. The Swift Playgrounds app comes with a framework, 
>>> PlaygroundSupport, that can be used from within a playground. It's 
>>> important that when they upgrade the app, existing playgrounds don't break, 
>>> since the end user may not have access to the entire code of the 
>>> playground. (Remember that playgrounds are often authored by one developer 
>>> or group, but then run and modified by someone else with a much lower skill 
>>> level!) That means that PlaygroundSupport can't currently vend any enums 
>>> that they expect playground authors to exhaustively switch over.
>>> 
>>> (And to make it even more specific—and appealing—one of the enums they were 
>>> considering would be a representation of the Swift AST. This can obviously 
>>> change from release to release, but previous switch statements should stay 
>>> valid.)
>>> 
>>> Now, this is an example we know about, so we could certainly make it 
>>> explicitly non-exhaustive. But in general we're in the same situation as 
>>> 'open': if we want to be friendly to library authors, we need to make the 
>>> default thing be the one that promises less, even if it means a bit of 
>>> extra work in the "I-actually-own-everything" case.
>>> 
>>> Best,
>>> Jordan
>>> 
>>> 
 On Sep 15, 2017, at 15:47, Rex Fenley > wrote:
 
 Hey Jordan,
 
 Thank you for the time writing this up. I've been following along to the 
 discussion somewhat closely and have kept silent because `exhaustive` was 
 originally set to be the default for enums. However, that changed and so 
 I'd like to voice my opinion, I frankly don't like this idea.
 
 At remind we use algebraic data types religiously for managing state and 
 data and rely on exhaustive pattern matching to guarantee we're handling 
 all states in our code. We're splitting out our code across modules and 
 having this guarantee has been a joy to work with.
 
 The benefit of making nonexhaustive the default for Swift 5 across all 
 multi-module code (besides C code) seems minimal to me. If a developer 
 feels like they're unnecessarily managing enum cases, they can simply add 
 a `default` case whenever they please. This is already the case and I'm 
 curious if there's every been any complaints about this and what they 
 would be. I'd prefer to be cautious and force exhaustive pattern matching 
 in all possible cases and leave it up to the developer to choose not to.
 
 Ideally in my 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-20 Thread Rex Fenley via swift-evolution
Hi Jordan,

I've been keeping up with most of the discussion since I last emailed about
my concern about making nonexhaustive the default mode for enums. So far I
am still strongly in the camp of exhaustive by default.

Most of my understanding comes from the perspective of source
compatibility; since I'm primarily an iOS app developer and contributor to
open source through CocoaPods, I don't have enough experience with binary
compatibility issues to understand the breadth of the effects of such a
change on binary compatibility - so I will argue from the perspective of
source compatibility. Additionally, all the following applies exclusively
to enums from Swift and not Obj-C/C. Largely my concerns stem from the "default
effect "-
whatever default is chosen is going to unconsciously bias developers to use
that default.

To start, I don't follow how nonexhaustive by default leads to more secure
code or promises less. In a world where nonexhaustive is default,
hard-to-track bugs will be introduced frequently into many Swift
developer's code.

   - Evolving contracts - The change you suggest leaves it up to the user
   to remember to add new cases into their code if an enum ever does change in
   a framework, and their code relies on exhaustive pattern matching.
   - Unhandled case bugs - This will lead to inconsistencies and
   hard-to-track bugs, since it would require the user to then track down an
   unhandled case that they may not even be aware exists (forcing googling,
   searching through documentation, etc.).

This is something that I certainly have experienced in the past working
across teams programming in Obj-C, and Swift has so far completely
eliminated this class of bugs! In a world where exhaustive remains default,
nothing changes, fewer bugs.

Next off is developer usability. As someone who has contributed to several
frameworks in Swift, one thing I know is that you can always count on
people complaining about the usability of their library - it's something
you learn to expect. If it turns out that people are very frustrated with
an enum constantly changing and breaking compatibility, they will voice
that concern with a thousand  on github, debate will happen, and the
appropriate course correction will be made. In this case, no real damage
done.

That said, if enums are nonexhaustive by default, frameworks will have more
nonexhaustive enums (as it becomes convention). The class of bugs
previously discussed will emerge, causing real damage to users and
developers. Complaints will arise, but with more hostility. In this case,
we end up back where we started, since framework developers will then mark
exhaustive for all their enums. The only difference is that it'll be
something that must be remembered to be done.

I can understand how someone developing an Apple framework may want
nonexhaustive by default, since enums from some Apple libraries seem to be
much larger and change relatively often. Yet, from my experience, this
doesn't represent what you find in open source libraries that seem to land
on something consistent and then stick with it. And that consistency pairs
very well with exhaustiveness.

Given this, it's clear that adding a case to an enum as a source breaking
change should be the expected behavior. It's safer for those using the
frameworks, and back propagation from users will correct it if it becomes
an annoyance. Nonexhaustive as a keyword is a nice additional tool to make
this correction simpler (as well as protect C enums by default), but should
not be the standard.

Best,
Rex

On Fri, Sep 15, 2017 at 5:06 PM, Jordan Rose  wrote:

> Hi, Rex. I definitely agree that 'exhaustive' is the right model for a
> multi-module app; indeed, there's no real reason for a single project to do
> anything else. However, it is not always the right behavior for libraries
> that actually get distributed, whether as source or as binary. In this case
> we want to minimize the error of omission: in the app case, forgetting
> "exhaustive" is an annoyance that you notice and fix once across your code
> base, but in the library case forgetting the "default case" means putting
> out a source-breaking release, and for libraries that have binary
> compatibility constraints there's no recourse at all.
>
> While most of the proposal deals with the experience we've had with the
> Apple SDKs (as written in Objective-C), we actually *have* run into this
> case in Swift already. The Swift Playgrounds app comes with a framework,
> PlaygroundSupport, that can be used from within a playground. It's
> important that when they upgrade the app, existing playgrounds don't break,
> since the end user may not have access to the entire code of the
> playground. (Remember that playgrounds are often authored by one developer
> or group, but then run and modified by someone else with a much lower skill
> level!) *That* means that 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-19 Thread Vladimir.S via swift-evolution
I'd like to discuss a processing of nonexhaustive external enums(imported from 
separate module/framework) a little more.


I understand that we (in most cases) don't want to exhaustively check some C's 
declared enum which is used for some system's API etc.

But what about 'usual' libraries distributed as framework/module?

Do you agree that:

1. In most cases external enums(public enums declared in *separate module*) will be 
nonexhaustive, because library developer don't want to crash consumer's code if later 
will be decided that one more enum case is needed in that public enum.
Enums like Optional, that should be exhaustive, will be rare in compare to "usual" 
enums like ButtonType, PaymentMethod, LoginKind etc


2. So, almost any enum coming from separate module/framework, even if library 
designer *wants* user's code to process that enum exhaustive(and it is perfectly 
logically to process it exhaustively in some places of user's code), will be declared 
as 'nonexhaustive' *just* to preserve binary compatibility if new case will be added.


3. So we actually will lose a compiler's help to work with most of such 
external enums.

4. If you ever need to support a code with exhaustive switch regarding external 
'nonexhaustive' enum(and as noted above, most of such enums will be nonexhaustive) - 
you are in a big trouble, you'll need to manually check for each newer version of 
used library(module) if there are new cases in used enums for each switch in your 
code, or try to find a 3rd party tools that will help with this. But given you have 
'default' in your switch - how the tool can say that you want tot be exhaustive here?


?

Also, please consider the two examples below. Is there incorrect logic/assumption 
used in any of them?


1. Let's say I have a Shapes enum in my library, which is distributes as separate 
module/framework. Each shape will have its own properties(like radius for .circle, 
side length for .square, angle and lengths for .line etc). Will I defined it as 
'exhaustive' ? No. It is very possible, that I'll add some cases into the enum and I 
don't want to break user's code. Is it possible that user's code want to switch 
exhaustive on this enum? Of course, but there is no support for this in compiler.
Can user's code work with new(future) enums? It depends, but *this is possible*, for 
example it can process only known cases, and show some warning like "unknown items 
found, please update to latest version of app" instead of crash.


2.
* I'm using a framework(separate module) that exports Things enum.
* This framework provides user's code with [Things] array
* I show each 'thing'(let's say its 'title' property) from that array in TableView 
per row
* By selecting a row, I show a details page for selected thing. Information on 
details page depends on associated value for the selected 'thing'
* For unsupported(future) 'things' I'll show only title for it in TableView and 
'Unsupported' marker. Details page will not be available for it, until I update the 
program. When selecting it, alert will show something like "Unknown type of thing. 
Please update the app to support new things".
* Is it required for me to be able to exhaustive switch of such enum? Yes, I need 
this to process all known cases in Details page. Exactly why we need exhaustive 
switch for 'internal' enums. But no compiler's help in this case.


I just want to say, if I understand correctly, that enum declared in separate 
module/framework will usually be 'nonexhaustive' even if library developer expects 
user's code to exhaustive switch on that enum. And that we really need a way to be 
exhaustive in switch in our code regarding imported enum which is declared as 
'nonexhaustive' in its module.


Thank you for attention and your time.
Vladimir.

On 18.09.2017 20:23, Jordan Rose via swift-evolution wrote:



On Sep 16, 2017, at 15:35, Kenny Leung via swift-evolution 
> wrote:


In general, I agree with everything in the proposal.

I’d like to propose these alternative extensions for clients:

1) As a client of an enum, I’d like to know in the future when a new value has been 
added to an enum, since I may have to do something about it. How about adding the 
“exhaustive” keyword to be used in the switch statement? Like


exhaustive switch excuse {
case eatenByPet:
// …
case thoughtItWasDueNextWeek:
// …
default:
// …
}

If exhaustive is used, there would be a warning if all cases aren’t covered *even 
though default exists*. This means that I as the client thought I had everything 
covered when I wrote this code.


As already mentioned, this makes the default case un-testable, which brings me 
to

2) All non-exhaustive enums should have the pseudo value “default” that can be used 
just like a regular value. This would allow you to write code like:


teacher.failedToHandInHomework(excuse: .default)

which would allow you 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Sep 17, 2017, at 5:02 PM, Jonathan Hull  wrote:
> 
> 
>> On Sep 17, 2017, at 7:55 AM, Matthew Johnson  wrote:
>> 
>> 
>> 
>> Sent from my iPad
>> 
>>> On Sep 17, 2017, at 3:37 AM, Jonathan Hull via swift-evolution 
>>>  wrote:
>>> 
>>> I run into use cases like this all the time…
>>> 
>>> I think I would prefer to see those concrete cases in a subtype though:
>>> 
>>> enum DrinkSize {
>>> case small
>>> case medium
>>> case large
>>> }
>>> 
>>> enum SummerDrinkSize : DrinkSize {
>>> //Inherits DrinkSize’s cases
>>> case extraLarge
>>> }
>>> 
>>> Because it is a subtype, you could place a SummerDrinkSize anywhere you can 
>>> put a DrinkSize.  As a result, all switches on it would need a default case 
>>> to handle cases they hadn’t planned for. If you mark an enum with “final” 
>>> then it can’t be extended and switches can be exhaustive.
>> 
>> You have the subtype relationship backwards here.  DrinkSize is a subtype of 
>> SummerDrinkSize.  All values of DrinkSize are also valid values of 
>> SummerDrinkSize but not vice versa.  For this reason, inheritance syntax 
>> doesn't make sense.  The syntax that makes more sense is some kind of case 
>> embedding syntax:
>> 
>> enum SummerDrinkSize {
>>  cases DrinkSize
>>  case extraLarge
>> }
> 
> I disagree.  I get that the shape of a DrinkSize would always fit in a 
> SummerDrinkSize hole (ignoring the overriding/extension of methods), but the 
> fact that we are requiring ‘default’ in switches changes the calculus.  
> Basically, it changed when we decided to change whether exhaustive was the 
> default.  The point is to make people consider that they may have cases which 
> they may not expect.  That is much easier with a concrete idea of subtype, 
> which people are already used to.

Requiring developers to consider cases that may be added to an enum in the 
future is orthogonal to any potential subtype relationship between two value 
types.

> 
> 
>>> 
>>> In addition to inheriting the cases, a subtype would also inherit, and be 
>>> able to override, methods defined on the super-type.  You could use super 
>>> to call the super-type’s implementation. 
>> 
>> I think implementation sharing is a bad idea for value types.  Value 
>> subtyping should be conceptualized as a restricted mechanism for 
>> value-preserving implicit conversion.
> 
> Why?

First, this is how value subtyping already works in the case of Optional where 
`T` is a subtype of `T?`.

More generally, this approach is roughly analogous to implicit promotion in 
C-family languages.  We want `Int8` to be a subtype of `Int16`, `Int32`, `Int`, 
etc.

This approach allows a value type to have multiple value-preserving supertypes 
without the performance impact of dynamic dispatch or the complexity of 
multiple inheritance.

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread David Hart via swift-evolution

> On 18 Sep 2017, at 19:20, Jordan Rose  wrote:
> 
> That's pretty much the same as this proposal except you don't have the new 
> keyword. I'm not sure why that really makes a difference, since they're 
> obviously paired, and it would limit existing libraries from declaring 
> exhaustive enums until they've moved entirely to Swift 5 mode. I think the 
> current proposal makes sense as is.

The difference is that it reduces the keyword soup and removes a keyword that 
will be the default behavior enums have in Swift 5. If we follow the same 
reasoning, why don’t we have nonfinal, @nonescaping, @nonDiscardableResult? Is 
it really worth adding a keyword only to support libraries while they 
transition to Swift 5?

> Jordan
> 
> 
>> On Sep 16, 2017, at 01:55, David Hart  wrote:
>> 
>> I’m still very much bothered by having 2 new keywords. I would really prefer 
>> the following plan:
>> 
>> Exhaustive by default in Swift 4
>> No new keyword in Swift 4 to change that behaviour
>> Non-exhaustive by default outside the module in Swift 5
>> exhaustive keyword to change the default behaviour
>> 
>> Like that, we don’t need nonexhaustive.
>> 
>> Thoughts?
>> David.
>> 
>>> On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution 
>>>  wrote:
>>> 
>>> Proposal updated, same URL: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md.
>>> 
>>> Thanks again for all the feedback so far, everyone!
>>> Jordan
>>> 
>>> 
 On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
  wrote:
 
 Sorry, I got distracted by other tasks! Both the discussion here and 
 within Apple has moved towards making "non-exhaustive" the default, which, 
 to be honest, I too think is the best design. I'll update the proposal 
 today to reflect that, though I still want to keep both the 
 "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for 
 now (or whatever we end up naming them). The compatibility design is a 
 little less ambitious than Brent's; as currently proposed, Swift 4 mode 
 continues to default to 'exhaustive' all the time, even in the actual 
 Swift 5 release.
 
 I still want to respond to Brent's points directly, but I think you and 
 Vladimir have done a good job discussing them already. I'll send out the 
 updated proposal tomorrow, after I have a little more time to think about 
 #invalid.
 
 Thanks for putting time into this!
 Jordan
 
 
> On Sep 9, 2017, at 17:34, Rod Brown  wrote:
> 
> Jordan,
> 
> Do you have any other thoughts about the ongoing discussion here, 
> especially regarding Chris’ comments? As you’re the one pushing this 
> forward, I’d really like to know what your thoughts are regarding this?
> 
> - Rod
 
 ___
 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
>> 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Kenny Leung via swift-evolution
“… what you're describing isn't really an enum"

I’ve gotten this explanation before in reference to errors. I am confused as to 
what constitutes an enum and what doesn’t. 

-Kenny


> On Sep 18, 2017, at 10:31 AM, Jordan Rose  wrote:
> 
> As mentioned, the right way to do this is with a struct:
> 
> public struct ConnectionDictionaryKey: RawRepresentable, Hashable {
>   public var rawValue: String
>   public init(rawValue: String) { … }
>   public init(_ rawValue: String) { … }
> }
> extension ConnectionDictionaryKey {
>   static let hostName = ConnectionDictionaryKey("hostname")
>   static let databaseName = ConnectionDictionaryKey("database")
>   // …
> }
> 
> It is definitely more verbose than an enum, and it may be worth a separate 
> proposal to deal with that! But it is not part of this proposal, and what 
> you're describing isn't really an enum.
> 
> Jordan
> 
> 
>> On Sep 16, 2017, at 15:51, Kenny Leung via swift-evolution 
>> > wrote:
>> 
>> Oops, forgot something:
>> 
>> "Can there be a kind of open enum where you can add new cases in extensions?”
>> 
>> I have a use case for this. I’m trying to write a database ORM with abstract 
>> API and concrete instances for different database. So I have defined:
>> 
>> open class Database {
>>init(connectionDictionary: [ConnectionDictionaryKey:String]) {
>> self.connectionDictionary = connectionDictionary;
>> }
>> }
>> 
>> Where I have ConnectionDictionaryKey defined as an enum, with values like 
>> .hostName, .databaseName, .userName, .password, .databaseName, etc…
>> 
>> But concrete databases may have other options that need to be added to the 
>> connection dictionary. It would be nice if they could just extend 
>> ConnectionDictionaryKey with new cases.
>> 
>> -Kenny
>> 
>> 
>>> On Sep 16, 2017, at 3:35 PM, Kenny Leung via swift-evolution 
>>> > wrote:
>>> 
>>> In general, I agree with everything in the proposal.
>>> 
>>> I’d like to propose these alternative extensions for clients:
>>> 
>>> 1) As a client of an enum, I’d like to know in the future when a new value 
>>> has been added to an enum, since I may have to do something about it. How 
>>> about adding the “exhaustive” keyword to be used in the switch statement? 
>>> Like
>>> 
>>> exhaustive switch excuse {
>>> case eatenByPet:
>>> // …
>>> case thoughtItWasDueNextWeek:
>>> // …
>>> default:
>>> // …
>>> }
>>> 
>>> If exhaustive is used, there would be a warning if all cases aren’t covered 
>>> *even though default exists*. This means that I as the client thought I had 
>>> everything covered when I wrote this code.
>>> 
>>> As already mentioned, this makes the default case un-testable, which brings 
>>> me to
>>> 
>>> 2) All non-exhaustive enums should have the pseudo value “default” that can 
>>> be used just like a regular value. This would allow you to write code like:
>>> 
>>> teacher.failedToHandInHomework(excuse: .default)
>>> 
>>> which would allow you to trip the default case in any code you may write.
>>> 
>>> -Kenny
>>> 
>>> 
 On Sep 13, 2017, at 12:17 PM, Jordan Rose via swift-evolution 
 > wrote:
 
 Proposal updated, same URL: 
 https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
  
 .
 
 Thanks again for all the feedback so far, everyone!
 Jordan
 
 
> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
> > wrote:
> 
> Sorry, I got distracted by other tasks! Both the discussion here and 
> within Apple has moved towards making "non-exhaustive" the default, 
> which, to be honest, I too think is the best design. I'll update the 
> proposal today to reflect that, though I still want to keep both the 
> "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for 
> now (or whatever we end up naming them). The compatibility design is a 
> little less ambitious than Brent's; as currently proposed, Swift 4 mode 
> continues to default to 'exhaustive' all the time, even in the actual 
> Swift 5 release.
> 
> I still want to respond to Brent's points directly, but I think you and 
> Vladimir have done a good job discussing them already. I'll send out the 
> updated proposal tomorrow, after I have a little more time to think about 
> #invalid.
> 
> Thanks for putting time into this!
> Jordan
> 
> 
>> On Sep 9, 2017, at 17:34, Rod Brown > > wrote:
>> 
>> Jordan,
>> 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Kenny Leung via swift-evolution
Ah, I get it now. Even if the switch knows what to do with the unknown value, 
the rest of your code would have to know what to do with it, and that is 
unlikely.

-Kenny


> On Sep 18, 2017, at 10:23 AM, Jordan Rose  wrote:
> 
> 
> 
>> On Sep 16, 2017, at 15:35, Kenny Leung via swift-evolution 
>> > wrote:
>> 
>> In general, I agree with everything in the proposal.
>> 
>> I’d like to propose these alternative extensions for clients:
>> 
>> 1) As a client of an enum, I’d like to know in the future when a new value 
>> has been added to an enum, since I may have to do something about it. How 
>> about adding the “exhaustive” keyword to be used in the switch statement? 
>> Like
>> 
>> exhaustive switch excuse {
>> case eatenByPet:
>> // …
>> case thoughtItWasDueNextWeek:
>> // …
>> default:
>> // …
>> }
>> 
>> If exhaustive is used, there would be a warning if all cases aren’t covered 
>> *even though default exists*. This means that I as the client thought I had 
>> everything covered when I wrote this code.
>> 
>> As already mentioned, this makes the default case un-testable, which brings 
>> me to
>> 
>> 2) All non-exhaustive enums should have the pseudo value “default” that can 
>> be used just like a regular value. This would allow you to write code like:
>> 
>> teacher.failedToHandInHomework(excuse: .default)
>> 
>> which would allow you to trip the default case in any code you may write.
> 
> Brent came up with this idea as well, but after thinking it through Joe Groff 
> and I found that it doesn't really work in practice:
> 
>> It’s going to be very common to have a future value and hand it right back 
>> to the framework without looking at it, for example:
>> 
>> override func process(_ transaction: @testable Transaction) {
>>   switch transaction {
>>   case .deposit(let amount):
>> // …
>>   case .withdrawal(let amount):
>> // …
>>   default:
>> super.process(transaction) // hmm…
>>   }
>> }
>> 
>> So just making it to the ‘default’ case doesn’t guarantee that it’s testable 
>> in practice.
> 
> I'll add the actual code here to the "Testing invalid cases" section under 
> "Alternatives considered", since that's a clearer example than the paragraph 
> I wrote. (Oh, and the "exhaustive switch" is equivalent to the section on 
> "'future' cases".)
> 
> Thanks for the feedback!
> Jordan

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Jordan Rose via swift-evolution
I don't think unit tests help much here. In the case where an 'exhaustive' enum 
ought to be 'nonexhaustive', unit tests wouldn't help you catch the issue until 
you tried adding a new case. And in both cases, a unit test would only help if 
you tried to switch exhaustively over the enum, something you may not think to 
write (depending on what the enum is, of course).

In either direction, there's a potential error of omission, and if you've 
"omitted" the annotation from your library code I wouldn't assume you'd 
remember to check that specific thing in a unit test.

Jordan


> On Sep 16, 2017, at 00:44, Goffredo Marocchi  wrote:
> 
> Sorry for being naive, but aside from open (and the decision not to make it 
> the default which again hurts the users of the library),  wouldn’t the 
> playground library example be ok if the framework author had validated it 
> with unit tests?
> 
> Sent from my iPhone
> 
> On 16 Sep 2017, at 01:07, Jordan Rose via swift-evolution 
> > wrote:
> 
>> Hi, Rex. I definitely agree that 'exhaustive' is the right model for a 
>> multi-module app; indeed, there's no real reason for a single project to do 
>> anything else. However, it is not always the right behavior for libraries 
>> that actually get distributed, whether as source or as binary. In this case 
>> we want to minimize the error of omission: in the app case, forgetting 
>> "exhaustive" is an annoyance that you notice and fix once across your code 
>> base, but in the library case forgetting the "default case" means putting 
>> out a source-breaking release, and for libraries that have binary 
>> compatibility constraints there's no recourse at all.
>> 
>> While most of the proposal deals with the experience we've had with the 
>> Apple SDKs (as written in Objective-C), we actually have run into this case 
>> in Swift already. The Swift Playgrounds app comes with a framework, 
>> PlaygroundSupport, that can be used from within a playground. It's important 
>> that when they upgrade the app, existing playgrounds don't break, since the 
>> end user may not have access to the entire code of the playground. (Remember 
>> that playgrounds are often authored by one developer or group, but then run 
>> and modified by someone else with a much lower skill level!) That means that 
>> PlaygroundSupport can't currently vend any enums that they expect playground 
>> authors to exhaustively switch over.
>> 
>> (And to make it even more specific—and appealing—one of the enums they were 
>> considering would be a representation of the Swift AST. This can obviously 
>> change from release to release, but previous switch statements should stay 
>> valid.)
>> 
>> Now, this is an example we know about, so we could certainly make it 
>> explicitly non-exhaustive. But in general we're in the same situation as 
>> 'open': if we want to be friendly to library authors, we need to make the 
>> default thing be the one that promises less, even if it means a bit of extra 
>> work in the "I-actually-own-everything" case.
>> 
>> Best,
>> Jordan
>> 
>> 
>>> On Sep 15, 2017, at 15:47, Rex Fenley >> > wrote:
>>> 
>>> Hey Jordan,
>>> 
>>> Thank you for the time writing this up. I've been following along to the 
>>> discussion somewhat closely and have kept silent because `exhaustive` was 
>>> originally set to be the default for enums. However, that changed and so 
>>> I'd like to voice my opinion, I frankly don't like this idea.
>>> 
>>> At remind we use algebraic data types religiously for managing state and 
>>> data and rely on exhaustive pattern matching to guarantee we're handling 
>>> all states in our code. We're splitting out our code across modules and 
>>> having this guarantee has been a joy to work with.
>>> 
>>> The benefit of making nonexhaustive the default for Swift 5 across all 
>>> multi-module code (besides C code) seems minimal to me. If a developer 
>>> feels like they're unnecessarily managing enum cases, they can simply add a 
>>> `default` case whenever they please. This is already the case and I'm 
>>> curious if there's every been any complaints about this and what they would 
>>> be. I'd prefer to be cautious and force exhaustive pattern matching in all 
>>> possible cases and leave it up to the developer to choose not to.
>>> 
>>> Ideally in my mind, these keywords won't be necessary. All Swift enums will 
>>> remain as they are, exhaustively pattern matched by default. Enums from C 
>>> code will be explicitly nonexhaustive in all cases.
>>> 
>>> -- 
>>> Rex Fenley  |  IOS DEVELOPER
>>> 
>>> 
>>> Remind.com  |  BLOG   |  
>>> FOLLOW US   |  LIKE US 
>>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Jon Shier via swift-evolution
Since I was just looking at the Default section, it wasn’t clear that 
the default was just for the external case. But mostly I just wasn’t paying 
close attention. Also, it’s not entirely clear whether nonexhaustive enums can 
be used within the same module, but again, I may just be missing something.



Jon

> On Sep 18, 2017, at 1:09 PM, Jordan Rose  wrote:
> 
> That is in fact what the proposal states:
> 
>> Currently, adding a new case to an enum is a source-breaking change, which 
>> is very inconvenient for library authors. This proposal aims to distinguish 
>> between enums that are exhaustive (meaning they will never get any new 
>> cases) and those that are non-exhaustive, and to ensure that clients handle 
>> any future cases when dealing with the latter. This change only affects 
>> clients from outside the original module.
> 
>> When a client tries to switch over a nonexhaustive enum, they must include a 
>> default case unless the enum is declared in the same module as the switch.
> 
> Do you have any suggestions on how to make this clearer in the proposal?
> 
> Jordan
> 
> 
>> On Sep 15, 2017, at 21:40, Jon Shier > > wrote:
>> 
>>  In that case Jordan, can Swift not treat it like open? i.e. Internally 
>> to a module, unmarked enums are still exhaustive by default, but when made 
>> public and used beyond the module, it becomes non-exhaustive? I think this 
>> has been discussed before and perhaps discarded as confusing, but it doesn’t 
>> seem to be any more confusing than open being the default internally and 
>> closed the default publicly. Otherwise you’re essentially forcing what is 
>> likely the vast majority of enum usage to adopt a bit of boilerplate that 
>> will only be used by the vast minority of libraries (almost entirely 
>> libraries shipped by Apple). 
>> 
>> 
>> Jon
>> 
>>> On Sep 15, 2017, at 8:07 PM, Jordan Rose via swift-evolution 
>>> > wrote:
>>> 
>>> Hi, Rex. I definitely agree that 'exhaustive' is the right model for a 
>>> multi-module app; indeed, there's no real reason for a single project to do 
>>> anything else. However, it is not always the right behavior for libraries 
>>> that actually get distributed, whether as source or as binary. In this case 
>>> we want to minimize the error of omission: in the app case, forgetting 
>>> "exhaustive" is an annoyance that you notice and fix once across your code 
>>> base, but in the library case forgetting the "default case" means putting 
>>> out a source-breaking release, and for libraries that have binary 
>>> compatibility constraints there's no recourse at all.
>>> 
>>> While most of the proposal deals with the experience we've had with the 
>>> Apple SDKs (as written in Objective-C), we actually have run into this case 
>>> in Swift already. The Swift Playgrounds app comes with a framework, 
>>> PlaygroundSupport, that can be used from within a playground. It's 
>>> important that when they upgrade the app, existing playgrounds don't break, 
>>> since the end user may not have access to the entire code of the 
>>> playground. (Remember that playgrounds are often authored by one developer 
>>> or group, but then run and modified by someone else with a much lower skill 
>>> level!) That means that PlaygroundSupport can't currently vend any enums 
>>> that they expect playground authors to exhaustively switch over.
>>> 
>>> (And to make it even more specific—and appealing—one of the enums they were 
>>> considering would be a representation of the Swift AST. This can obviously 
>>> change from release to release, but previous switch statements should stay 
>>> valid.)
>>> 
>>> Now, this is an example we know about, so we could certainly make it 
>>> explicitly non-exhaustive. But in general we're in the same situation as 
>>> 'open': if we want to be friendly to library authors, we need to make the 
>>> default thing be the one that promises less, even if it means a bit of 
>>> extra work in the "I-actually-own-everything" case.
>>> 
>>> Best,
>>> Jordan
>>> 
>>> 
 On Sep 15, 2017, at 15:47, Rex Fenley > wrote:
 
 Hey Jordan,
 
 Thank you for the time writing this up. I've been following along to the 
 discussion somewhat closely and have kept silent because `exhaustive` was 
 originally set to be the default for enums. However, that changed and so 
 I'd like to voice my opinion, I frankly don't like this idea.
 
 At remind we use algebraic data types religiously for managing state and 
 data and rely on exhaustive pattern matching to guarantee we're handling 
 all states in our code. We're splitting out our code across modules and 
 having this guarantee has been a joy to work with.
 
 The benefit of making nonexhaustive the default for Swift 5 across all 
 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Jordan Rose via swift-evolution
As mentioned, the right way to do this is with a struct:

public struct ConnectionDictionaryKey: RawRepresentable, Hashable {
  public var rawValue: String
  public init(rawValue: String) { … }
  public init(_ rawValue: String) { … }
}
extension ConnectionDictionaryKey {
  static let hostName = ConnectionDictionaryKey("hostname")
  static let databaseName = ConnectionDictionaryKey("database")
  // …
}

It is definitely more verbose than an enum, and it may be worth a separate 
proposal to deal with that! But it is not part of this proposal, and what 
you're describing isn't really an enum.

Jordan


> On Sep 16, 2017, at 15:51, Kenny Leung via swift-evolution 
>  wrote:
> 
> Oops, forgot something:
> 
> "Can there be a kind of open enum where you can add new cases in extensions?”
> 
> I have a use case for this. I’m trying to write a database ORM with abstract 
> API and concrete instances for different database. So I have defined:
> 
> open class Database {
>init(connectionDictionary: [ConnectionDictionaryKey:String]) {
> self.connectionDictionary = connectionDictionary;
> }
> }
> 
> Where I have ConnectionDictionaryKey defined as an enum, with values like 
> .hostName, .databaseName, .userName, .password, .databaseName, etc…
> 
> But concrete databases may have other options that need to be added to the 
> connection dictionary. It would be nice if they could just extend 
> ConnectionDictionaryKey with new cases.
> 
> -Kenny
> 
> 
>> On Sep 16, 2017, at 3:35 PM, Kenny Leung via swift-evolution 
>> > wrote:
>> 
>> In general, I agree with everything in the proposal.
>> 
>> I’d like to propose these alternative extensions for clients:
>> 
>> 1) As a client of an enum, I’d like to know in the future when a new value 
>> has been added to an enum, since I may have to do something about it. How 
>> about adding the “exhaustive” keyword to be used in the switch statement? 
>> Like
>> 
>> exhaustive switch excuse {
>> case eatenByPet:
>> // …
>> case thoughtItWasDueNextWeek:
>> // …
>> default:
>> // …
>> }
>> 
>> If exhaustive is used, there would be a warning if all cases aren’t covered 
>> *even though default exists*. This means that I as the client thought I had 
>> everything covered when I wrote this code.
>> 
>> As already mentioned, this makes the default case un-testable, which brings 
>> me to
>> 
>> 2) All non-exhaustive enums should have the pseudo value “default” that can 
>> be used just like a regular value. This would allow you to write code like:
>> 
>> teacher.failedToHandInHomework(excuse: .default)
>> 
>> which would allow you to trip the default case in any code you may write.
>> 
>> -Kenny
>> 
>> 
>>> On Sep 13, 2017, at 12:17 PM, Jordan Rose via swift-evolution 
>>> > wrote:
>>> 
>>> Proposal updated, same URL: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>>  
>>> .
>>> 
>>> Thanks again for all the feedback so far, everyone!
>>> Jordan
>>> 
>>> 
 On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
 > wrote:
 
 Sorry, I got distracted by other tasks! Both the discussion here and 
 within Apple has moved towards making "non-exhaustive" the default, which, 
 to be honest, I too think is the best design. I'll update the proposal 
 today to reflect that, though I still want to keep both the 
 "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for 
 now (or whatever we end up naming them). The compatibility design is a 
 little less ambitious than Brent's; as currently proposed, Swift 4 mode 
 continues to default to 'exhaustive' all the time, even in the actual 
 Swift 5 release.
 
 I still want to respond to Brent's points directly, but I think you and 
 Vladimir have done a good job discussing them already. I'll send out the 
 updated proposal tomorrow, after I have a little more time to think about 
 #invalid.
 
 Thanks for putting time into this!
 Jordan
 
 
> On Sep 9, 2017, at 17:34, Rod Brown  > wrote:
> 
> Jordan,
> 
> Do you have any other thoughts about the ongoing discussion here, 
> especially regarding Chris’ comments? As you’re the one pushing this 
> forward, I’d really like to know what your thoughts are regarding this?
> 
> - Rod
 
 ___
 swift-evolution mailing list
 swift-evolution@swift.org 
 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Jordan Rose via swift-evolution


> On Sep 16, 2017, at 15:35, Kenny Leung via swift-evolution 
>  wrote:
> 
> In general, I agree with everything in the proposal.
> 
> I’d like to propose these alternative extensions for clients:
> 
> 1) As a client of an enum, I’d like to know in the future when a new value 
> has been added to an enum, since I may have to do something about it. How 
> about adding the “exhaustive” keyword to be used in the switch statement? Like
> 
> exhaustive switch excuse {
> case eatenByPet:
> // …
> case thoughtItWasDueNextWeek:
> // …
> default:
> // …
> }
> 
> If exhaustive is used, there would be a warning if all cases aren’t covered 
> *even though default exists*. This means that I as the client thought I had 
> everything covered when I wrote this code.
> 
> As already mentioned, this makes the default case un-testable, which brings 
> me to
> 
> 2) All non-exhaustive enums should have the pseudo value “default” that can 
> be used just like a regular value. This would allow you to write code like:
> 
> teacher.failedToHandInHomework(excuse: .default)
> 
> which would allow you to trip the default case in any code you may write.

Brent came up with this idea as well, but after thinking it through Joe Groff 
and I found that it doesn't really work in practice:

> It’s going to be very common to have a future value and hand it right back to 
> the framework without looking at it, for example:
> 
> override func process(_ transaction: @testable Transaction) {
>   switch transaction {
>   case .deposit(let amount):
> // …
>   case .withdrawal(let amount):
> // …
>   default:
> super.process(transaction) // hmm…
>   }
> }
> 
> So just making it to the ‘default’ case doesn’t guarantee that it’s testable 
> in practice.

I'll add the actual code here to the "Testing invalid cases" section under 
"Alternatives considered", since that's a clearer example than the paragraph I 
wrote. (Oh, and the "exhaustive switch" is equivalent to the section on 
"'future' cases".)

Thanks for the feedback!
Jordan___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Jordan Rose via swift-evolution
That's pretty much the same as this proposal except you don't have the new 
keyword. I'm not sure why that really makes a difference, since they're 
obviously paired, and it would limit existing libraries from declaring 
exhaustive enums until they've moved entirely to Swift 5 mode. I think the 
current proposal makes sense as is.

Jordan


> On Sep 16, 2017, at 01:55, David Hart  wrote:
> 
> I’m still very much bothered by having 2 new keywords. I would really prefer 
> the following plan:
> 
> Exhaustive by default in Swift 4
> No new keyword in Swift 4 to change that behaviour
> Non-exhaustive by default outside the module in Swift 5
> exhaustive keyword to change the default behaviour
> 
> Like that, we don’t need nonexhaustive.
> 
> Thoughts?
> David.
> 
>> On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> Proposal updated, same URL: 
>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>  
>> .
>> 
>> Thanks again for all the feedback so far, everyone!
>> Jordan
>> 
>> 
>>> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
>>> > wrote:
>>> 
>>> Sorry, I got distracted by other tasks! Both the discussion here and within 
>>> Apple has moved towards making "non-exhaustive" the default, which, to be 
>>> honest, I too think is the best design. I'll update the proposal today to 
>>> reflect that, though I still want to keep both the "nonexhaustive" and 
>>> "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end 
>>> up naming them). The compatibility design is a little less ambitious than 
>>> Brent's; as currently proposed, Swift 4 mode continues to default to 
>>> 'exhaustive' all the time, even in the actual Swift 5 release.
>>> 
>>> I still want to respond to Brent's points directly, but I think you and 
>>> Vladimir have done a good job discussing them already. I'll send out the 
>>> updated proposal tomorrow, after I have a little more time to think about 
>>> #invalid.
>>> 
>>> Thanks for putting time into this!
>>> Jordan
>>> 
>>> 
 On Sep 9, 2017, at 17:34, Rod Brown > wrote:
 
 Jordan,
 
 Do you have any other thoughts about the ongoing discussion here, 
 especially regarding Chris’ comments? As you’re the one pushing this 
 forward, I’d really like to know what your thoughts are regarding this?
 
 - Rod
>>> 
>>> ___
>>> 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
> 

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Jordan Rose via swift-evolution


> On Sep 16, 2017, at 11:35, Christopher Kornher via swift-evolution 
>  wrote:
> 
> 
> 
> 
> 
>> On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution 
>> > wrote:
>> 
>>> 
>>> On Sep 16, 2017, at 8:41 AM, Rod Brown via swift-evolution 
>>> > wrote:
>>> 
>>> 
>>> On 16 Sep 2017, at 7:22 pm, Goffredo Marocchi via swift-evolution 
>>> > wrote:
>>> 
 I am still unsure why we are choosing again a default that protects 
 library writers more than library users where it is reasonable to expect 
 the former to have better mastery of the language, to architect a library 
 with some scalability, and ability to add unit test to cover themselves 
 from issues than the latter.
>>> 
>>> Because protecting library owners protects library users.
>> 
>> If a library writer can’t remember to declare non-exhaustive enums as such, 
>> they probably will forget many more important aspects of creating a library. 
>> They probably should not be writing libraries. Arguments like this make 
>> sense on the surface, but creating libraries involves hundreds or thousands 
>> of decisions. I wish you luck in making that process idiot proof. A library 
>> linter could easily warn that exposed enums are exhaustive. The exhaustive 
>> keyword should be optional to make the decision obvious and suppress 
>> warnings. Complicating the user experience in a vain attempt to make 
>> “expert" coding safer is misguided.
> 
> This may be a little harsh, but there don’t seem to be many advocates for 
> novice and “ordinary” application developers on this list. That is not 
> unexpected given the number of extremely knowledgeable compiler and library 
> developers on this list (for whom I have the highest respect). I believe that 
> there are more creative (and probably more difficult to build) possible 
> solutions to some of the tough problems in Swift’s future. In that spirit, 
> see below.

It's definitely good to consider the effects on normal application developers!


> 
>> 
>> 
>>> 
>>> If you declare it is exhaustive and it was an oversight, and then realise 
>>> after the fact that you are wrong, you have to open it up. This will break 
>>> third party apps. It will be disallowed by the ABI compatibility 
>>> requirements.
>>> 
>>> If you declare it isn’t exhaustive due to an oversight (or perhaps you’re 
>>> just not sure yet), and then realise after the fact it is exhaustive, you 
>>> can close it up. This will not break third party apps. It will also be 
>>> allowed for ABI compatibility.
>>> 
>>> This benefits everyone. Make library owners choose a guarantee, rather than 
>>> be defaulted into it. Much like they have to declare choose to declare 
>>> “final” on a class: you can’t retroactively reneg that promise: it will 
>>> break everyone who assumed it to be the case!
>> 
>> It does not benefit the creation of 90+% of enums. It is one more arcane 
>> rule for the vast majority of developers.
> 
> The Swift compiler could offer a “strict enum exhaustiveness” (bikeshedding 
> not included) switch that could be enabled by default for library targets and 
> disabled by default for “application” targets. The switch would make not 
> explicitly specifying exhaustiveness an error or warning when enabled. 
> Perhaps this could be combined with other options that would tailor the 
> development experience for library/application developers. This would help 
> avoid “zero-sum” choices between benefitting library or application 
> developers in the future.
> 
> Xcode and the SPM should be able to distinguish between the target types and 
> generate the proper defaults. I do not believe that this is too mysterious 
> for developers. There would be learning step for developers wiring their 
> first library, but that is not necessarily a bad thing since creating a 
> reusable library requires a different mindset than creating an application.

Right now we have this notion, but the difference between library and app is 
signified by "public". My opinion is that between the choices of "multi-module 
applications have to deal with everything SwiftPM packages do" and "there are 
different rules for multi-module applications and for SwiftPM packages", the 
former is preferable just in terms of overall complexity in the language. It's 
certainly a trade-off! But that's what I'm proposing, and it should be very 
clear what to do when multi-module app developers encounter the additional 
rules that come with, well, having multiple modules.

(We're already likely to have an extra distinction between "libraries built 
with support for binary compatibility" and "libraries built to be distributed 
with their clients", but it's still better if that too avoids splitting the 
language into dialects.)


Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Jordan Rose via swift-evolution
That is in fact what the proposal states:

> Currently, adding a new case to an enum is a source-breaking change, which is 
> very inconvenient for library authors. This proposal aims to distinguish 
> between enums that are exhaustive (meaning they will never get any new cases) 
> and those that are non-exhaustive, and to ensure that clients handle any 
> future cases when dealing with the latter. This change only affects clients 
> from outside the original module.

> When a client tries to switch over a nonexhaustive enum, they must include a 
> default case unless the enum is declared in the same module as the switch.

Do you have any suggestions on how to make this clearer in the proposal?

Jordan


> On Sep 15, 2017, at 21:40, Jon Shier  wrote:
> 
>   In that case Jordan, can Swift not treat it like open? i.e. Internally 
> to a module, unmarked enums are still exhaustive by default, but when made 
> public and used beyond the module, it becomes non-exhaustive? I think this 
> has been discussed before and perhaps discarded as confusing, but it doesn’t 
> seem to be any more confusing than open being the default internally and 
> closed the default publicly. Otherwise you’re essentially forcing what is 
> likely the vast majority of enum usage to adopt a bit of boilerplate that 
> will only be used by the vast minority of libraries (almost entirely 
> libraries shipped by Apple). 
> 
> 
> Jon
> 
>> On Sep 15, 2017, at 8:07 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> Hi, Rex. I definitely agree that 'exhaustive' is the right model for a 
>> multi-module app; indeed, there's no real reason for a single project to do 
>> anything else. However, it is not always the right behavior for libraries 
>> that actually get distributed, whether as source or as binary. In this case 
>> we want to minimize the error of omission: in the app case, forgetting 
>> "exhaustive" is an annoyance that you notice and fix once across your code 
>> base, but in the library case forgetting the "default case" means putting 
>> out a source-breaking release, and for libraries that have binary 
>> compatibility constraints there's no recourse at all.
>> 
>> While most of the proposal deals with the experience we've had with the 
>> Apple SDKs (as written in Objective-C), we actually have run into this case 
>> in Swift already. The Swift Playgrounds app comes with a framework, 
>> PlaygroundSupport, that can be used from within a playground. It's important 
>> that when they upgrade the app, existing playgrounds don't break, since the 
>> end user may not have access to the entire code of the playground. (Remember 
>> that playgrounds are often authored by one developer or group, but then run 
>> and modified by someone else with a much lower skill level!) That means that 
>> PlaygroundSupport can't currently vend any enums that they expect playground 
>> authors to exhaustively switch over.
>> 
>> (And to make it even more specific—and appealing—one of the enums they were 
>> considering would be a representation of the Swift AST. This can obviously 
>> change from release to release, but previous switch statements should stay 
>> valid.)
>> 
>> Now, this is an example we know about, so we could certainly make it 
>> explicitly non-exhaustive. But in general we're in the same situation as 
>> 'open': if we want to be friendly to library authors, we need to make the 
>> default thing be the one that promises less, even if it means a bit of extra 
>> work in the "I-actually-own-everything" case.
>> 
>> Best,
>> Jordan
>> 
>> 
>>> On Sep 15, 2017, at 15:47, Rex Fenley >> > wrote:
>>> 
>>> Hey Jordan,
>>> 
>>> Thank you for the time writing this up. I've been following along to the 
>>> discussion somewhat closely and have kept silent because `exhaustive` was 
>>> originally set to be the default for enums. However, that changed and so 
>>> I'd like to voice my opinion, I frankly don't like this idea.
>>> 
>>> At remind we use algebraic data types religiously for managing state and 
>>> data and rely on exhaustive pattern matching to guarantee we're handling 
>>> all states in our code. We're splitting out our code across modules and 
>>> having this guarantee has been a joy to work with.
>>> 
>>> The benefit of making nonexhaustive the default for Swift 5 across all 
>>> multi-module code (besides C code) seems minimal to me. If a developer 
>>> feels like they're unnecessarily managing enum cases, they can simply add a 
>>> `default` case whenever they please. This is already the case and I'm 
>>> curious if there's every been any complaints about this and what they would 
>>> be. I'd prefer to be cautious and force exhaustive pattern matching in all 
>>> possible cases and leave it up to the developer to choose not to.
>>> 
>>> Ideally in my mind, these keywords won't be necessary. All 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Jon Shier via swift-evolution
I just noticed this too. I guess I was looking too closely at the 
“Default behavior” section.The inlining caveat scares me a little, as it would 
seem to have rather drastic consequences in the future, essentially requiring 
the worst case scenario, even in the same module, if we want inlining for 
functions that use enums.


Jon

> On Sep 17, 2017, at 9:09 PM, Rod Brown via swift-evolution 
>  wrote:
> 
>> 
>> On 18 Sep 2017, at 9:46 am, Christopher Kornher > > wrote:
>> 
>> 
>>> On Sep 17, 2017, at 5:04 PM, BJ Homer >> > wrote:
>>> 
>>> Please note that, as proposed, enums are always treated as exhaustive 
>>> *within the same module*. A new user writing MyFirstEnum is likely using it 
>>> within the same module, and will thus get exhaustive behavior with no extra 
>>> keywords required.
>> 
>> • What is your evaluation of the proposal?
>>  Uh, +1
>> 
>>  • How much effort did you put into your review? A glance, a quick reading, 
>> or an in-depth study?
>>  not enough
>> 
>> Apologies for wasting everyone’s time…
> 
> Haha no problems. Yes, it seems clear people are jumping to conclusions. This 
> is a case specifically for framework developers purely for interface 
> consistency, with is *exactly* when you want the default behaviour to protect 
> you from external dependency changes.
> 
> Within the context of a single application at compile time, you will always 
> know all cases already and therefore exhaustive can become the default. Cross 
> frameworks, not so much.
> 
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-17 Thread Rod Brown via swift-evolution

> On 18 Sep 2017, at 9:46 am, Christopher Kornher  wrote:
> 
> 
>> On Sep 17, 2017, at 5:04 PM, BJ Homer > > wrote:
>> 
>> Please note that, as proposed, enums are always treated as exhaustive 
>> *within the same module*. A new user writing MyFirstEnum is likely using it 
>> within the same module, and will thus get exhaustive behavior with no extra 
>> keywords required.
> 
> • What is your evaluation of the proposal?
>   Uh, +1
> 
>  • How much effort did you put into your review? A glance, a quick reading, 
> or an in-depth study?
>   not enough
> 
> Apologies for wasting everyone’s time…

Haha no problems. Yes, it seems clear people are jumping to conclusions. This 
is a case specifically for framework developers purely for interface 
consistency, with is *exactly* when you want the default behaviour to protect 
you from external dependency changes.

Within the context of a single application at compile time, you will always 
know all cases already and therefore exhaustive can become the default. Cross 
frameworks, not so much.


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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-17 Thread Jonathan Hull via swift-evolution
Ah, ok.  I had missed this too, somehow.

> On Sep 17, 2017, at 4:04 PM, BJ Homer via swift-evolution 
>  wrote:
> 
> Please note that, as proposed, enums are always treated as exhaustive *within 
> the same module*. A new user writing MyFirstEnum is likely using it within 
> the same module, and will thus get exhaustive behavior with no extra keywords 
> required.
> 
> -BJ
> 
> On Sep 17, 2017, at 3:20 PM, Christopher Kornher via swift-evolution 
> > wrote:
> 
>> 
>>> On Sep 17, 2017, at 6:33 AM, Rod Brown via swift-evolution 
>>> > wrote:
>>> 
>>> 
 On 17 Sep 2017, at 4:35 am, Christopher Kornher > wrote:
 
> On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution 
> > wrote:
> 
> If a library writer can’t remember to declare non-exhaustive enums as 
> such, they probably will forget many more important aspects of creating a 
> library. They probably should not be writing libraries. Arguments like 
> this make sense on the surface, but creating libraries involves hundreds 
> or thousands of decisions. I wish you luck in making that process idiot 
> proof. A library linter could easily warn that exposed enums are 
> exhaustive. The exhaustive keyword should be optional to make the 
> decision obvious and suppress warnings. Complicating the user experience 
> in a vain attempt to make “expert" coding safer is misguided.
>>> 
>>> I think the same logic goes both ways: If a library author can’t remember 
>>> to declare exhaustive enums as such, they will probably forget many more 
>>> important aspects of creating a library.
>>> 
>>> The problem here is fundamental: Exhaustive is a guarantee. A guarantee 
>>> should require action. Non-Exhaustive guarantees nothing. It makes you 
>>> safer. That is all.
>> 
>> 1) Exhaustive enums are inherently better: they allow a developer to know 
>> that they have covered all possible cases by not using a default.
>> 2) This proposal forces developers to add a keyword to get this behavior in 
>> their apps, which is common to all other languages with enums that I have 
>> used. This proposal breaks the model common to all (?) current 
>> implementations of enums. 
>> 
>> 
>>> 
 
 This may be a little harsh, but there don’t seem to be many advocates for 
 novice and “ordinary” application developers on this list. That is not 
 unexpected given the number of extremely knowledgeable compiler and 
 library developers on this list (for whom I have the highest respect). I 
 believe that there are more creative (and probably more difficult to 
 build) possible solutions to some of the tough problems in Swift’s future. 
 In that spirit, see below.
>>> 
>>> I personally am an “ordinary” application developer.
>>> 
>>> I think the issue here is that everyone is seeing Swift as *they* intend to 
>>> use it. For App Devs, exhaustive switches are nice, which means they really 
>>> are fighting tooth and nail to keep them. I understand that. But I’m also 
>>> trying to keep my mind open for “what happens to an app I compiled in iOS 
>>> 15 that I compiled for iOS 11?” And this gives me pause. I can’t ask Apple 
>>> or any other library author to be completely knowledgable about every case 
>>> in the future, and to audit every line of code and manually give 
>>> non-exhaustive.
>>> 
>>> Why do people want “exhaustive” to be the default?
>>> Because we like things as they are.
>> 
>> No, because it makes sense to make common things easy and uncommon things 
>> possible. 
>> 
>>> Because we like not having to consider edge cases. Because we want to 
>>> imagine that will give framework developers the control to make our lives 
>>> difficult because they’ll just be lazy and make our lives hard by not 
>>> annotating. And this certainly is a concern. But I think a larger concern 
>>> is breaking apps left, right and centre, or not being able to extend 
>>> frameworks because an earlier developer on a project made an oversight.
>> 
>> This happens all the time: Apple deprecates APIs and asked developers to use 
>> new ones. If a library writer does not run (the as-yet hypothetical ) 
>> library lint, not participate in thorough code reviews,…, they can simply 
>> create a new non-exhaustive enum and deprecate the old one. Yes, there will 
>> be some redundant function calls for a while, but again, similar things 
>> happen, even in APIs like Apple’s, that (one hopes, at least) are thoroughly 
>> reviewed. It is not the end of the world to deprecate and migrate APIs. You  
>> may remember garbage collected Objective-C, the change that “viewWillAppear” 
>> suddenly was not called when it used to be in iOS. We all survived the 
>> 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-17 Thread Jonathan Hull via swift-evolution

> On Sep 17, 2017, at 7:55 AM, Matthew Johnson  wrote:
> 
> 
> 
> Sent from my iPad
> 
> On Sep 17, 2017, at 3:37 AM, Jonathan Hull via swift-evolution 
> > wrote:
> 
>> I run into use cases like this all the time…
>> 
>> I think I would prefer to see those concrete cases in a subtype though:
>> 
>>  enum DrinkSize {
>>  case small
>>  case medium
>>  case large
>>  }
>> 
>>  enum SummerDrinkSize : DrinkSize {
>>  //Inherits DrinkSize’s cases
>>  case extraLarge
>>  }
>> 
>> Because it is a subtype, you could place a SummerDrinkSize anywhere you can 
>> put a DrinkSize.  As a result, all switches on it would need a default case 
>> to handle cases they hadn’t planned for. If you mark an enum with “final” 
>> then it can’t be extended and switches can be exhaustive.
> 
> You have the subtype relationship backwards here.  DrinkSize is a subtype of 
> SummerDrinkSize.  All values of DrinkSize are also valid values of 
> SummerDrinkSize but not vice versa.  For this reason, inheritance syntax 
> doesn't make sense.  The syntax that makes more sense is some kind of case 
> embedding syntax:
> 
> enum SummerDrinkSize {
>   cases DrinkSize
>   case extraLarge
> }

I disagree.  I get that the shape of a DrinkSize would always fit in a 
SummerDrinkSize hole (ignoring the overriding/extension of methods), but the 
fact that we are requiring ‘default’ in switches changes the calculus.  
Basically, it changed when we decided to change whether exhaustive was the 
default.  The point is to make people consider that they may have cases which 
they may not expect.  That is much easier with a concrete idea of subtype, 
which people are already used to.


>> 
>> In addition to inheriting the cases, a subtype would also inherit, and be 
>> able to override, methods defined on the super-type.  You could use super to 
>> call the super-type’s implementation. 
> 
> I think implementation sharing is a bad idea for value types.  Value 
> subtyping should be conceptualized as a restricted mechanism for 
> value-preserving implicit conversion.

Why?


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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-17 Thread Christopher Kornher via swift-evolution

> On Sep 17, 2017, at 5:04 PM, BJ Homer  wrote:
> 
> Please note that, as proposed, enums are always treated as exhaustive *within 
> the same module*. A new user writing MyFirstEnum is likely using it within 
> the same module, and will thus get exhaustive behavior with no extra keywords 
> required.

• What is your evaluation of the proposal?
Uh, +1

 • How much effort did you put into your review? A glance, a quick reading, or 
an in-depth study?
not enough

Apologies for wasting everyone’s time...

> -BJ
> 
> On Sep 17, 2017, at 3:20 PM, Christopher Kornher via swift-evolution 
> > wrote:
> 
>> 
>>> On Sep 17, 2017, at 6:33 AM, Rod Brown via swift-evolution 
>>> > wrote:
>>> 
>>> 
 On 17 Sep 2017, at 4:35 am, Christopher Kornher > wrote:
 
> On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution 
> > wrote:
> 
> If a library writer can’t remember to declare non-exhaustive enums as 
> such, they probably will forget many more important aspects of creating a 
> library. They probably should not be writing libraries. Arguments like 
> this make sense on the surface, but creating libraries involves hundreds 
> or thousands of decisions. I wish you luck in making that process idiot 
> proof. A library linter could easily warn that exposed enums are 
> exhaustive. The exhaustive keyword should be optional to make the 
> decision obvious and suppress warnings. Complicating the user experience 
> in a vain attempt to make “expert" coding safer is misguided.
>>> 
>>> I think the same logic goes both ways: If a library author can’t remember 
>>> to declare exhaustive enums as such, they will probably forget many more 
>>> important aspects of creating a library.
>>> 
>>> The problem here is fundamental: Exhaustive is a guarantee. A guarantee 
>>> should require action. Non-Exhaustive guarantees nothing. It makes you 
>>> safer. That is all.
>> 
>> 1) Exhaustive enums are inherently better: they allow a developer to know 
>> that they have covered all possible cases by not using a default.
>> 2) This proposal forces developers to add a keyword to get this behavior in 
>> their apps, which is common to all other languages with enums that I have 
>> used. This proposal breaks the model common to all (?) current 
>> implementations of enums. 
>> 
>> 
>>> 
 
 This may be a little harsh, but there don’t seem to be many advocates for 
 novice and “ordinary” application developers on this list. That is not 
 unexpected given the number of extremely knowledgeable compiler and 
 library developers on this list (for whom I have the highest respect). I 
 believe that there are more creative (and probably more difficult to 
 build) possible solutions to some of the tough problems in Swift’s future. 
 In that spirit, see below.
>>> 
>>> I personally am an “ordinary” application developer.
>>> 
>>> I think the issue here is that everyone is seeing Swift as *they* intend to 
>>> use it. For App Devs, exhaustive switches are nice, which means they really 
>>> are fighting tooth and nail to keep them. I understand that. But I’m also 
>>> trying to keep my mind open for “what happens to an app I compiled in iOS 
>>> 15 that I compiled for iOS 11?” And this gives me pause. I can’t ask Apple 
>>> or any other library author to be completely knowledgable about every case 
>>> in the future, and to audit every line of code and manually give 
>>> non-exhaustive.
>>> 
>>> Why do people want “exhaustive” to be the default?
>>> Because we like things as they are.
>> 
>> No, because it makes sense to make common things easy and uncommon things 
>> possible. 
>> 
>>> Because we like not having to consider edge cases. Because we want to 
>>> imagine that will give framework developers the control to make our lives 
>>> difficult because they’ll just be lazy and make our lives hard by not 
>>> annotating. And this certainly is a concern. But I think a larger concern 
>>> is breaking apps left, right and centre, or not being able to extend 
>>> frameworks because an earlier developer on a project made an oversight.
>> 
>> This happens all the time: Apple deprecates APIs and asked developers to use 
>> new ones. If a library writer does not run (the as-yet hypothetical ) 
>> library lint, not participate in thorough code reviews,…, they can simply 
>> create a new non-exhaustive enum and deprecate the old one. Yes, there will 
>> be some redundant function calls for a while, but again, similar things 
>> happen, even in APIs like Apple’s, that (one hopes, at least) are thoroughly 
>> reviewed. It is not the end of the world to deprecate and migrate APIs. You  
>> may 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-17 Thread BJ Homer via swift-evolution
Please note that, as proposed, enums are always treated as exhaustive *within 
the same module*. A new user writing MyFirstEnum is likely using it within the 
same module, and will thus get exhaustive behavior with no extra keywords 
required.

-BJ

> On Sep 17, 2017, at 3:20 PM, Christopher Kornher via swift-evolution 
>  wrote:
> 
> 
>>> On Sep 17, 2017, at 6:33 AM, Rod Brown via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On 17 Sep 2017, at 4:35 am, Christopher Kornher  wrote:
 
 On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution 
  wrote:
 
 If a library writer can’t remember to declare non-exhaustive enums as 
 such, they probably will forget many more important aspects of creating a 
 library. They probably should not be writing libraries. Arguments like 
 this make sense on the surface, but creating libraries involves hundreds 
 or thousands of decisions. I wish you luck in making that process idiot 
 proof. A library linter could easily warn that exposed enums are 
 exhaustive. The exhaustive keyword should be optional to make the decision 
 obvious and suppress warnings. Complicating the user experience in a vain 
 attempt to make “expert" coding safer is misguided.
>> 
>> I think the same logic goes both ways: If a library author can’t remember to 
>> declare exhaustive enums as such, they will probably forget many more 
>> important aspects of creating a library.
>> 
>> The problem here is fundamental: Exhaustive is a guarantee. A guarantee 
>> should require action. Non-Exhaustive guarantees nothing. It makes you 
>> safer. That is all.
> 
> 1) Exhaustive enums are inherently better: they allow a developer to know 
> that they have covered all possible cases by not using a default.
> 2) This proposal forces developers to add a keyword to get this behavior in 
> their apps, which is common to all other languages with enums that I have 
> used. This proposal breaks the model common to all (?) current 
> implementations of enums. 
> 
> 
>> 
>>> 
>>> This may be a little harsh, but there don’t seem to be many advocates for 
>>> novice and “ordinary” application developers on this list. That is not 
>>> unexpected given the number of extremely knowledgeable compiler and library 
>>> developers on this list (for whom I have the highest respect). I believe 
>>> that there are more creative (and probably more difficult to build) 
>>> possible solutions to some of the tough problems in Swift’s future. In that 
>>> spirit, see below.
>> 
>> I personally am an “ordinary” application developer.
>> 
>> I think the issue here is that everyone is seeing Swift as *they* intend to 
>> use it. For App Devs, exhaustive switches are nice, which means they really 
>> are fighting tooth and nail to keep them. I understand that. But I’m also 
>> trying to keep my mind open for “what happens to an app I compiled in iOS 15 
>> that I compiled for iOS 11?” And this gives me pause. I can’t ask Apple or 
>> any other library author to be completely knowledgable about every case in 
>> the future, and to audit every line of code and manually give non-exhaustive.
>> 
>> Why do people want “exhaustive” to be the default?
>> Because we like things as they are.
> 
> No, because it makes sense to make common things easy and uncommon things 
> possible. 
> 
>> Because we like not having to consider edge cases. Because we want to 
>> imagine that will give framework developers the control to make our lives 
>> difficult because they’ll just be lazy and make our lives hard by not 
>> annotating. And this certainly is a concern. But I think a larger concern is 
>> breaking apps left, right and centre, or not being able to extend frameworks 
>> because an earlier developer on a project made an oversight.
> 
> This happens all the time: Apple deprecates APIs and asked developers to use 
> new ones. If a library writer does not run (the as-yet hypothetical ) library 
> lint, not participate in thorough code reviews,…, they can simply create a 
> new non-exhaustive enum and deprecate the old one. Yes, there will be some 
> redundant function calls for a while, but again, similar things happen, even 
> in APIs like Apple’s, that (one hopes, at least) are thoroughly reviewed. It 
> is not the end of the world to deprecate and migrate APIs. You  may remember 
> garbage collected Objective-C, the change that “viewWillAppear” suddenly was 
> not called when it used to be in iOS. We all survived the elimination of GC 
> and moving our view initialization code. Libraries and developers can survive 
> mistakes and improvements.
> 
> ABI stability does not require foolproof, immutable, ABIs. In essence, it is 
> just a guarantee that the build system won’t require rebuilds if library 
> source code stays the same, or is added to, not that applications will never 
> have to be 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-17 Thread Rod Brown via swift-evolution

> On 17 Sep 2017, at 4:35 am, Christopher Kornher  wrote:
> 
>> On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution 
>> > wrote:
>> 
>> If a library writer can’t remember to declare non-exhaustive enums as such, 
>> they probably will forget many more important aspects of creating a library. 
>> They probably should not be writing libraries. Arguments like this make 
>> sense on the surface, but creating libraries involves hundreds or thousands 
>> of decisions. I wish you luck in making that process idiot proof. A library 
>> linter could easily warn that exposed enums are exhaustive. The exhaustive 
>> keyword should be optional to make the decision obvious and suppress 
>> warnings. Complicating the user experience in a vain attempt to make 
>> “expert" coding safer is misguided.

I think the same logic goes both ways: If a library author can’t remember to 
declare exhaustive enums as such, they will probably forget many more important 
aspects of creating a library.

The problem here is fundamental: Exhaustive is a guarantee. A guarantee should 
require action. Non-Exhaustive guarantees nothing. It makes you safer. That is 
all.

> 
> This may be a little harsh, but there don’t seem to be many advocates for 
> novice and “ordinary” application developers on this list. That is not 
> unexpected given the number of extremely knowledgeable compiler and library 
> developers on this list (for whom I have the highest respect). I believe that 
> there are more creative (and probably more difficult to build) possible 
> solutions to some of the tough problems in Swift’s future. In that spirit, 
> see below.

I personally am an “ordinary” application developer.

I think the issue here is that everyone is seeing Swift as *they* intend to use 
it. For App Devs, exhaustive switches are nice, which means they really are 
fighting tooth and nail to keep them. I understand that. But I’m also trying to 
keep my mind open for “what happens to an app I compiled in iOS 15 that I 
compiled for iOS 11?” And this gives me pause. I can’t ask Apple or any other 
library author to be completely knowledgable about every case in the future, 
and to audit every line of code and manually give non-exhaustive.

Why do people want “exhaustive” to be the default? Because we like things as 
they are. Because we like not having to consider edge cases. Because we want to 
imagine that will give framework developers the control to make our lives 
difficult because they’ll just be lazy and make our lives hard by not 
annotating. And this certainly is a concern. But I think a larger concern is 
breaking apps left, right and centre, or not being able to extend frameworks 
because an earlier developer on a project made an oversight.

Its in everyone’s best interest to think before we put handcuffs on, no matter 
how painful that is. Even if that means you make apps where you just write 
“default: fatalError(“I don’t handle unreachable defaults”)"

And lets be clear: Swift isn’t an app development language. It also isn’t a 
framework development language. It’s a multipurpose language designed to Take 
Over The World™. This means we need to think holistically about what is better 
for everyone. Not just ourselves.

> 
>> 
>> 
>>> 
>>> If you declare it is exhaustive and it was an oversight, and then realise 
>>> after the fact that you are wrong, you have to open it up. This will break 
>>> third party apps. It will be disallowed by the ABI compatibility 
>>> requirements.
>>> 
>>> If you declare it isn’t exhaustive due to an oversight (or perhaps you’re 
>>> just not sure yet), and then realise after the fact it is exhaustive, you 
>>> can close it up. This will not break third party apps. It will also be 
>>> allowed for ABI compatibility.
>>> 
>>> This benefits everyone. Make library owners choose a guarantee, rather than 
>>> be defaulted into it. Much like they have to declare choose to declare 
>>> “final” on a class: you can’t retroactively reneg that promise: it will 
>>> break everyone who assumed it to be the case!
>> 
>> It does not benefit the creation of 90+% of enums. It is one more arcane 
>> rule for the vast majority of developers.
> 
> The Swift compiler could offer a “strict enum exhaustiveness” (bikeshedding 
> not included) switch that could be enabled by default for library targets and 
> disabled by default for “application” targets. The switch would make not 
> explicitly specifying exhaustiveness an error or warning when enabled. 
> Perhaps this could be combined with other options that would tailor the 
> development experience for library/application developers. This would help 
> avoid “zero-sum” choices between benefitting library or application 
> developers in the future.

The Swift team have fundamentally opposed such pushes for “compiler modes” for 
a long time. I don’t expect they will embrace them now, nor do I 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-17 Thread Jonathan Hull via swift-evolution

> On Sep 16, 2017, at 11:35 AM, Christopher Kornher via swift-evolution 
>  wrote:
> 
> This may be a little harsh, but there don’t seem to be many advocates for 
> novice and “ordinary” application developers on this list. That is not 
> unexpected given the number of extremely knowledgeable compiler and library 
> developers on this list (for whom I have the highest respect). I believe that 
> there are more creative (and probably more difficult to build) possible 
> solutions to some of the tough problems in Swift’s future.

+1___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-17 Thread Jonathan Hull via swift-evolution
I run into use cases like this all the time…

I think I would prefer to see those concrete cases in a subtype though:

enum DrinkSize {
case small
case medium
case large
}

enum SummerDrinkSize : DrinkSize {
//Inherits DrinkSize’s cases
case extraLarge
}

Because it is a subtype, you could place a SummerDrinkSize anywhere you can put 
a DrinkSize.  As a result, all switches on it would need a default case to 
handle cases they hadn’t planned for. If you mark an enum with “final” then it 
can’t be extended and switches can be exhaustive.

In addition to inheriting the cases, a subtype would also inherit, and be able 
to override, methods defined on the super-type.  You could use super to call 
the super-type’s implementation. 

It is a bigger overhaul, but I think it actually ends up being semantically 
simpler for the end user.  Basically, you can do the same types of things you 
can with classes... with the same syntax (just without the reference-type-ness).

It just so happens that this would also solve the problem of adding cases to 
(non-final) library enums, because switches of the enums would need to handle 
default/unexpected cases.  That is a very abstract/confusing problem for end 
users who don’t write libraries to understand though.  I think it is much 
easier to explain “final” as being the same as it is in classes, in that it 
prevents subclassing… which means you know what all the cases are.

More work (also more powerful), but semantically simpler. It just combines 
concepts we already know...

Thanks,
Jon


> On Sep 16, 2017, at 3:51 PM, Kenny Leung via swift-evolution 
>  wrote:
> 
> Oops, forgot something:
> 
> "Can there be a kind of open enum where you can add new cases in extensions?”
> 
> I have a use case for this. I’m trying to write a database ORM with abstract 
> API and concrete instances for different database. So I have defined:
> 
> open class Database {
>init(connectionDictionary: [ConnectionDictionaryKey:String]) {
> self.connectionDictionary = connectionDictionary;
> }
> }
> 
> Where I have ConnectionDictionaryKey defined as an enum, with values like 
> .hostName, .databaseName, .userName, .password, .databaseName, etc…
> 
> But concrete databases may have other options that need to be added to the 
> connection dictionary. It would be nice if they could just extend 
> ConnectionDictionaryKey with new cases.
> 
> -Kenny
> 
> 
>> On Sep 16, 2017, at 3:35 PM, Kenny Leung via swift-evolution 
>> > wrote:
>> 
>> In general, I agree with everything in the proposal.
>> 
>> I’d like to propose these alternative extensions for clients:
>> 
>> 1) As a client of an enum, I’d like to know in the future when a new value 
>> has been added to an enum, since I may have to do something about it. How 
>> about adding the “exhaustive” keyword to be used in the switch statement? 
>> Like
>> 
>> exhaustive switch excuse {
>> case eatenByPet:
>> // …
>> case thoughtItWasDueNextWeek:
>> // …
>> default:
>> // …
>> }
>> 
>> If exhaustive is used, there would be a warning if all cases aren’t covered 
>> *even though default exists*. This means that I as the client thought I had 
>> everything covered when I wrote this code.
>> 
>> As already mentioned, this makes the default case un-testable, which brings 
>> me to
>> 
>> 2) All non-exhaustive enums should have the pseudo value “default” that can 
>> be used just like a regular value. This would allow you to write code like:
>> 
>> teacher.failedToHandInHomework(excuse: .default)
>> 
>> which would allow you to trip the default case in any code you may write.
>> 
>> -Kenny
>> 
>> 
>>> On Sep 13, 2017, at 12:17 PM, Jordan Rose via swift-evolution 
>>> > wrote:
>>> 
>>> Proposal updated, same URL: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>>  
>>> .
>>> 
>>> Thanks again for all the feedback so far, everyone!
>>> Jordan
>>> 
>>> 
 On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
 > wrote:
 
 Sorry, I got distracted by other tasks! Both the discussion here and 
 within Apple has moved towards making "non-exhaustive" the default, which, 
 to be honest, I too think is the best design. I'll update the proposal 
 today to reflect that, though I still want to keep both the 
 "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for 
 now (or whatever we end up naming them). The compatibility design is a 
 little less ambitious than 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-16 Thread Kenny Leung via swift-evolution
Oops, forgot something:

"Can there be a kind of open enum where you can add new cases in extensions?”

I have a use case for this. I’m trying to write a database ORM with abstract 
API and concrete instances for different database. So I have defined:

open class Database {
   init(connectionDictionary: [ConnectionDictionaryKey:String]) {
self.connectionDictionary = connectionDictionary;
}
}

Where I have ConnectionDictionaryKey defined as an enum, with values like 
.hostName, .databaseName, .userName, .password, .databaseName, etc…

But concrete databases may have other options that need to be added to the 
connection dictionary. It would be nice if they could just extend 
ConnectionDictionaryKey with new cases.

-Kenny


> On Sep 16, 2017, at 3:35 PM, Kenny Leung via swift-evolution 
>  wrote:
> 
> In general, I agree with everything in the proposal.
> 
> I’d like to propose these alternative extensions for clients:
> 
> 1) As a client of an enum, I’d like to know in the future when a new value 
> has been added to an enum, since I may have to do something about it. How 
> about adding the “exhaustive” keyword to be used in the switch statement? Like
> 
> exhaustive switch excuse {
> case eatenByPet:
> // …
> case thoughtItWasDueNextWeek:
> // …
> default:
> // …
> }
> 
> If exhaustive is used, there would be a warning if all cases aren’t covered 
> *even though default exists*. This means that I as the client thought I had 
> everything covered when I wrote this code.
> 
> As already mentioned, this makes the default case un-testable, which brings 
> me to
> 
> 2) All non-exhaustive enums should have the pseudo value “default” that can 
> be used just like a regular value. This would allow you to write code like:
> 
> teacher.failedToHandInHomework(excuse: .default)
> 
> which would allow you to trip the default case in any code you may write.
> 
> -Kenny
> 
> 
>> On Sep 13, 2017, at 12:17 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> Proposal updated, same URL: 
>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>  
>> .
>> 
>> Thanks again for all the feedback so far, everyone!
>> Jordan
>> 
>> 
>>> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
>>> > wrote:
>>> 
>>> Sorry, I got distracted by other tasks! Both the discussion here and within 
>>> Apple has moved towards making "non-exhaustive" the default, which, to be 
>>> honest, I too think is the best design. I'll update the proposal today to 
>>> reflect that, though I still want to keep both the "nonexhaustive" and 
>>> "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end 
>>> up naming them). The compatibility design is a little less ambitious than 
>>> Brent's; as currently proposed, Swift 4 mode continues to default to 
>>> 'exhaustive' all the time, even in the actual Swift 5 release.
>>> 
>>> I still want to respond to Brent's points directly, but I think you and 
>>> Vladimir have done a good job discussing them already. I'll send out the 
>>> updated proposal tomorrow, after I have a little more time to think about 
>>> #invalid.
>>> 
>>> Thanks for putting time into this!
>>> Jordan
>>> 
>>> 
 On Sep 9, 2017, at 17:34, Rod Brown > wrote:
 
 Jordan,
 
 Do you have any other thoughts about the ongoing discussion here, 
 especially regarding Chris’ comments? As you’re the one pushing this 
 forward, I’d really like to know what your thoughts are regarding this?
 
 - Rod
>>> 
>>> ___
>>> 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
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-16 Thread Kenny Leung via swift-evolution
In general, I agree with everything in the proposal.

I’d like to propose these alternative extensions for clients:

1) As a client of an enum, I’d like to know in the future when a new value has 
been added to an enum, since I may have to do something about it. How about 
adding the “exhaustive” keyword to be used in the switch statement? Like

exhaustive switch excuse {
case eatenByPet:
// …
case thoughtItWasDueNextWeek:
// …
default:
// …
}

If exhaustive is used, there would be a warning if all cases aren’t covered 
*even though default exists*. This means that I as the client thought I had 
everything covered when I wrote this code.

As already mentioned, this makes the default case un-testable, which brings me 
to

2) All non-exhaustive enums should have the pseudo value “default” that can be 
used just like a regular value. This would allow you to write code like:

teacher.failedToHandInHomework(excuse: .default)

which would allow you to trip the default case in any code you may write.

-Kenny


> On Sep 13, 2017, at 12:17 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> Proposal updated, same URL: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>  
> .
> 
> Thanks again for all the feedback so far, everyone!
> Jordan
> 
> 
>> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> Sorry, I got distracted by other tasks! Both the discussion here and within 
>> Apple has moved towards making "non-exhaustive" the default, which, to be 
>> honest, I too think is the best design. I'll update the proposal today to 
>> reflect that, though I still want to keep both the "nonexhaustive" and 
>> "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end 
>> up naming them). The compatibility design is a little less ambitious than 
>> Brent's; as currently proposed, Swift 4 mode continues to default to 
>> 'exhaustive' all the time, even in the actual Swift 5 release.
>> 
>> I still want to respond to Brent's points directly, but I think you and 
>> Vladimir have done a good job discussing them already. I'll send out the 
>> updated proposal tomorrow, after I have a little more time to think about 
>> #invalid.
>> 
>> Thanks for putting time into this!
>> Jordan
>> 
>> 
>>> On Sep 9, 2017, at 17:34, Rod Brown >> > wrote:
>>> 
>>> Jordan,
>>> 
>>> Do you have any other thoughts about the ongoing discussion here, 
>>> especially regarding Chris’ comments? As you’re the one pushing this 
>>> forward, I’d really like to know what your thoughts are regarding this?
>>> 
>>> - Rod
>> 
>> ___
>> 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

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-16 Thread Christopher Kornher via swift-evolution




> On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution 
>  wrote:
> 
>> 
>> On Sep 16, 2017, at 8:41 AM, Rod Brown via swift-evolution 
>> > wrote:
>> 
>> 
>> On 16 Sep 2017, at 7:22 pm, Goffredo Marocchi via swift-evolution 
>> > wrote:
>> 
>>> I am still unsure why we are choosing again a default that protects library 
>>> writers more than library users where it is reasonable to expect the former 
>>> to have better mastery of the language, to architect a library with some 
>>> scalability, and ability to add unit test to cover themselves from issues 
>>> than the latter.
>> 
>> Because protecting library owners protects library users.
> 
> If a library writer can’t remember to declare non-exhaustive enums as such, 
> they probably will forget many more important aspects of creating a library. 
> They probably should not be writing libraries. Arguments like this make sense 
> on the surface, but creating libraries involves hundreds or thousands of 
> decisions. I wish you luck in making that process idiot proof. A library 
> linter could easily warn that exposed enums are exhaustive. The exhaustive 
> keyword should be optional to make the decision obvious and suppress 
> warnings. Complicating the user experience in a vain attempt to make “expert" 
> coding safer is misguided.

This may be a little harsh, but there don’t seem to be many advocates for 
novice and “ordinary” application developers on this list. That is not 
unexpected given the number of extremely knowledgeable compiler and library 
developers on this list (for whom I have the highest respect). I believe that 
there are more creative (and probably more difficult to build) possible 
solutions to some of the tough problems in Swift’s future. In that spirit, see 
below.

> 
> 
>> 
>> If you declare it is exhaustive and it was an oversight, and then realise 
>> after the fact that you are wrong, you have to open it up. This will break 
>> third party apps. It will be disallowed by the ABI compatibility 
>> requirements.
>> 
>> If you declare it isn’t exhaustive due to an oversight (or perhaps you’re 
>> just not sure yet), and then realise after the fact it is exhaustive, you 
>> can close it up. This will not break third party apps. It will also be 
>> allowed for ABI compatibility.
>> 
>> This benefits everyone. Make library owners choose a guarantee, rather than 
>> be defaulted into it. Much like they have to declare choose to declare 
>> “final” on a class: you can’t retroactively reneg that promise: it will 
>> break everyone who assumed it to be the case!
> 
> It does not benefit the creation of 90+% of enums. It is one more arcane rule 
> for the vast majority of developers.

The Swift compiler could offer a “strict enum exhaustiveness” (bikeshedding not 
included) switch that could be enabled by default for library targets and 
disabled by default for “application” targets. The switch would make not 
explicitly specifying exhaustiveness an error or warning when enabled. Perhaps 
this could be combined with other options that would tailor the development 
experience for library/application developers. This would help avoid “zero-sum” 
choices between benefitting library or application developers in the future.

Xcode and the SPM should be able to distinguish between the target types and 
generate the proper defaults. I do not believe that this is too mysterious for 
developers. There would be learning step for developers wiring their first 
library, but that is not necessarily a bad thing since creating a reusable 
library requires a different mindset than creating an application.


> 
>> 
>>> 
>>> Exhaustive and open by default with keywords to close things down if the 
>>> framework author wants them.
>>> 
>>> Sent from my iPhone
>>> 
>>> On 16 Sep 2017, at 09:55, David Hart via swift-evolution 
>>> > wrote:
>>> 
 I’m still very much bothered by having 2 new keywords. I would really 
 prefer the following plan:
 
 Exhaustive by default in Swift 4
 No new keyword in Swift 4 to change that behaviour
 Non-exhaustive by default outside the module in Swift 5
 exhaustive keyword to change the default behaviour
 
 Like that, we don’t need nonexhaustive.
 
 Thoughts?
 David.
 
> On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution 
> > wrote:
> 
> Proposal updated, same URL: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>  
> .
> 
> Thanks again for all the feedback so far, 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-16 Thread Christopher Kornher via swift-evolution

> On Sep 16, 2017, at 8:41 AM, Rod Brown via swift-evolution 
>  wrote:
> 
> 
> On 16 Sep 2017, at 7:22 pm, Goffredo Marocchi via swift-evolution 
> > wrote:
> 
>> I am still unsure why we are choosing again a default that protects library 
>> writers more than library users where it is reasonable to expect the former 
>> to have better mastery of the language, to architect a library with some 
>> scalability, and ability to add unit test to cover themselves from issues 
>> than the latter.
> 
> Because protecting library owners protects library users.

If a library writer can’t remember to declare non-exhaustive enums as such, 
they probably will forget many more important aspects of creating a library. 
They probably should not be writing libraries. Arguments like this make sense 
on the surface, but creating libraries involves hundreds or thousands of 
decisions. I wish you luck in making that process idiot proof. A library linter 
could easily warn that exposed enums are exhaustive. The exhaustive keyword 
should be optional to make the decision obvious and suppress warnings. 
Complicating the user experience in a vain attempt to make “expert" coding 
safer is misguided.


> 
> If you declare it is exhaustive and it was an oversight, and then realise 
> after the fact that you are wrong, you have to open it up. This will break 
> third party apps. It will be disallowed by the ABI compatibility requirements.
> 
> If you declare it isn’t exhaustive due to an oversight (or perhaps you’re 
> just not sure yet), and then realise after the fact it is exhaustive, you can 
> close it up. This will not break third party apps. It will also be allowed 
> for ABI compatibility.
> 
> This benefits everyone. Make library owners choose a guarantee, rather than 
> be defaulted into it. Much like they have to declare choose to declare 
> “final” on a class: you can’t retroactively reneg that promise: it will break 
> everyone who assumed it to be the case!

It does not benefit the creation of 90+% of enums. It is one more arcane rule 
for the vast majority of developers.

> 
>> 
>> Exhaustive and open by default with keywords to close things down if the 
>> framework author wants them.
>> 
>> Sent from my iPhone
>> 
>> On 16 Sep 2017, at 09:55, David Hart via swift-evolution 
>> > wrote:
>> 
>>> I’m still very much bothered by having 2 new keywords. I would really 
>>> prefer the following plan:
>>> 
>>> Exhaustive by default in Swift 4
>>> No new keyword in Swift 4 to change that behaviour
>>> Non-exhaustive by default outside the module in Swift 5
>>> exhaustive keyword to change the default behaviour
>>> 
>>> Like that, we don’t need nonexhaustive.
>>> 
>>> Thoughts?
>>> David.
>>> 
 On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution 
 > wrote:
 
 Proposal updated, same URL: 
 https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
  
 .
 
 Thanks again for all the feedback so far, everyone!
 Jordan
 
 
> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
> > wrote:
> 
> Sorry, I got distracted by other tasks! Both the discussion here and 
> within Apple has moved towards making "non-exhaustive" the default, 
> which, to be honest, I too think is the best design. I'll update the 
> proposal today to reflect that, though I still want to keep both the 
> "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for 
> now (or whatever we end up naming them). The compatibility design is a 
> little less ambitious than Brent's; as currently proposed, Swift 4 mode 
> continues to default to 'exhaustive' all the time, even in the actual 
> Swift 5 release.
> 
> I still want to respond to Brent's points directly, but I think you and 
> Vladimir have done a good job discussing them already. I'll send out the 
> updated proposal tomorrow, after I have a little more time to think about 
> #invalid.
> 
> Thanks for putting time into this!
> Jordan
> 
> 
>> On Sep 9, 2017, at 17:34, Rod Brown > > wrote:
>> 
>> Jordan,
>> 
>> Do you have any other thoughts about the ongoing discussion here, 
>> especially regarding Chris’ comments? As you’re the one pushing this 
>> forward, I’d really like to know what your thoughts are regarding this?
>> 
>> - Rod
> 
> ___
> swift-evolution 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-16 Thread Rod Brown via swift-evolution

> On 16 Sep 2017, at 7:22 pm, Goffredo Marocchi via swift-evolution 
>  wrote:
> 
> I am still unsure why we are choosing again a default that protects library 
> writers more than library users where it is reasonable to expect the former 
> to have better mastery of the language, to architect a library with some 
> scalability, and ability to add unit test to cover themselves from issues 
> than the latter.

Because protecting library owners protects library users.

If you declare it is exhaustive and it was an oversight, and then realise after 
the fact that you are wrong, you have to open it up. This will break third 
party apps. It will be disallowed by the ABI compatibility requirements.

If you declare it isn’t exhaustive due to an oversight (or perhaps you’re just 
not sure yet), and then realise after the fact it is exhaustive, you can close 
it up. This will not break third party apps. It will also be allowed for ABI 
compatibility.

This benefits everyone. Make library owners choose a guarantee, rather than be 
defaulted into it. Much like they have to declare choose to declare “final” on 
a class: you can’t retroactively reneg that promise: it will break everyone who 
assumed it to be the case!

> 
> Exhaustive and open by default with keywords to close things down if the 
> framework author wants them.
> 
> Sent from my iPhone
> 
>> On 16 Sep 2017, at 09:55, David Hart via swift-evolution 
>>  wrote:
>> 
>> I’m still very much bothered by having 2 new keywords. I would really prefer 
>> the following plan:
>> 
>> Exhaustive by default in Swift 4
>> No new keyword in Swift 4 to change that behaviour
>> Non-exhaustive by default outside the module in Swift 5
>> exhaustive keyword to change the default behaviour
>> 
>> Like that, we don’t need nonexhaustive.
>> 
>> Thoughts?
>> David.
>> 
>>> On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution 
>>>  wrote:
>>> 
>>> Proposal updated, same URL: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md.
>>> 
>>> Thanks again for all the feedback so far, everyone!
>>> Jordan
>>> 
>>> 
 On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
  wrote:
 
 Sorry, I got distracted by other tasks! Both the discussion here and 
 within Apple has moved towards making "non-exhaustive" the default, which, 
 to be honest, I too think is the best design. I'll update the proposal 
 today to reflect that, though I still want to keep both the 
 "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for 
 now (or whatever we end up naming them). The compatibility design is a 
 little less ambitious than Brent's; as currently proposed, Swift 4 mode 
 continues to default to 'exhaustive' all the time, even in the actual 
 Swift 5 release.
 
 I still want to respond to Brent's points directly, but I think you and 
 Vladimir have done a good job discussing them already. I'll send out the 
 updated proposal tomorrow, after I have a little more time to think about 
 #invalid.
 
 Thanks for putting time into this!
 Jordan
 
 
> On Sep 9, 2017, at 17:34, Rod Brown  wrote:
> 
> Jordan,
> 
> Do you have any other thoughts about the ongoing discussion here, 
> especially regarding Chris’ comments? As you’re the one pushing this 
> forward, I’d really like to know what your thoughts are regarding this?
> 
> - Rod
 
 ___
 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
>> 
>> ___
>> 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
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-16 Thread Goffredo Marocchi via swift-evolution
I am still unsure why we are choosing again a default that protects library 
writers more than library users where it is reasonable to expect the former to 
have better mastery of the language, to architect a library with some 
scalability, and ability to add unit test to cover themselves from issues than 
the latter.

Exhaustive and open by default with keywords to close things down if the 
framework author wants them.

Sent from my iPhone

> On 16 Sep 2017, at 09:55, David Hart via swift-evolution 
>  wrote:
> 
> I’m still very much bothered by having 2 new keywords. I would really prefer 
> the following plan:
> 
> Exhaustive by default in Swift 4
> No new keyword in Swift 4 to change that behaviour
> Non-exhaustive by default outside the module in Swift 5
> exhaustive keyword to change the default behaviour
> 
> Like that, we don’t need nonexhaustive.
> 
> Thoughts?
> David.
> 
>> On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution 
>>  wrote:
>> 
>> Proposal updated, same URL: 
>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md.
>> 
>> Thanks again for all the feedback so far, everyone!
>> Jordan
>> 
>> 
>>> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
>>>  wrote:
>>> 
>>> Sorry, I got distracted by other tasks! Both the discussion here and within 
>>> Apple has moved towards making "non-exhaustive" the default, which, to be 
>>> honest, I too think is the best design. I'll update the proposal today to 
>>> reflect that, though I still want to keep both the "nonexhaustive" and 
>>> "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end 
>>> up naming them). The compatibility design is a little less ambitious than 
>>> Brent's; as currently proposed, Swift 4 mode continues to default to 
>>> 'exhaustive' all the time, even in the actual Swift 5 release.
>>> 
>>> I still want to respond to Brent's points directly, but I think you and 
>>> Vladimir have done a good job discussing them already. I'll send out the 
>>> updated proposal tomorrow, after I have a little more time to think about 
>>> #invalid.
>>> 
>>> Thanks for putting time into this!
>>> Jordan
>>> 
>>> 
 On Sep 9, 2017, at 17:34, Rod Brown  wrote:
 
 Jordan,
 
 Do you have any other thoughts about the ongoing discussion here, 
 especially regarding Chris’ comments? As you’re the one pushing this 
 forward, I’d really like to know what your thoughts are regarding this?
 
 - Rod
>>> 
>>> ___
>>> 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
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-16 Thread David Hart via swift-evolution
I’m still very much bothered by having 2 new keywords. I would really prefer 
the following plan:

Exhaustive by default in Swift 4
No new keyword in Swift 4 to change that behaviour
Non-exhaustive by default outside the module in Swift 5
exhaustive keyword to change the default behaviour

Like that, we don’t need nonexhaustive.

Thoughts?
David.

> On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution 
>  wrote:
> 
> Proposal updated, same URL: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>  
> .
> 
> Thanks again for all the feedback so far, everyone!
> Jordan
> 
> 
>> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> Sorry, I got distracted by other tasks! Both the discussion here and within 
>> Apple has moved towards making "non-exhaustive" the default, which, to be 
>> honest, I too think is the best design. I'll update the proposal today to 
>> reflect that, though I still want to keep both the "nonexhaustive" and 
>> "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end 
>> up naming them). The compatibility design is a little less ambitious than 
>> Brent's; as currently proposed, Swift 4 mode continues to default to 
>> 'exhaustive' all the time, even in the actual Swift 5 release.
>> 
>> I still want to respond to Brent's points directly, but I think you and 
>> Vladimir have done a good job discussing them already. I'll send out the 
>> updated proposal tomorrow, after I have a little more time to think about 
>> #invalid.
>> 
>> Thanks for putting time into this!
>> Jordan
>> 
>> 
>>> On Sep 9, 2017, at 17:34, Rod Brown >> > wrote:
>>> 
>>> Jordan,
>>> 
>>> Do you have any other thoughts about the ongoing discussion here, 
>>> especially regarding Chris’ comments? As you’re the one pushing this 
>>> forward, I’d really like to know what your thoughts are regarding this?
>>> 
>>> - Rod
>> 
>> ___
>> 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

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-16 Thread Goffredo Marocchi via swift-evolution
Sorry for being naive, but aside from open (and the decision not to make it the 
default which again hurts the users of the library),  wouldn’t the playground 
library example be ok if the framework author had validated it with unit tests?

Sent from my iPhone

> On 16 Sep 2017, at 01:07, Jordan Rose via swift-evolution 
>  wrote:
> 
> Hi, Rex. I definitely agree that 'exhaustive' is the right model for a 
> multi-module app; indeed, there's no real reason for a single project to do 
> anything else. However, it is not always the right behavior for libraries 
> that actually get distributed, whether as source or as binary. In this case 
> we want to minimize the error of omission: in the app case, forgetting 
> "exhaustive" is an annoyance that you notice and fix once across your code 
> base, but in the library case forgetting the "default case" means putting out 
> a source-breaking release, and for libraries that have binary compatibility 
> constraints there's no recourse at all.
> 
> While most of the proposal deals with the experience we've had with the Apple 
> SDKs (as written in Objective-C), we actually have run into this case in 
> Swift already. The Swift Playgrounds app comes with a framework, 
> PlaygroundSupport, that can be used from within a playground. It's important 
> that when they upgrade the app, existing playgrounds don't break, since the 
> end user may not have access to the entire code of the playground. (Remember 
> that playgrounds are often authored by one developer or group, but then run 
> and modified by someone else with a much lower skill level!) That means that 
> PlaygroundSupport can't currently vend any enums that they expect playground 
> authors to exhaustively switch over.
> 
> (And to make it even more specific—and appealing—one of the enums they were 
> considering would be a representation of the Swift AST. This can obviously 
> change from release to release, but previous switch statements should stay 
> valid.)
> 
> Now, this is an example we know about, so we could certainly make it 
> explicitly non-exhaustive. But in general we're in the same situation as 
> 'open': if we want to be friendly to library authors, we need to make the 
> default thing be the one that promises less, even if it means a bit of extra 
> work in the "I-actually-own-everything" case.
> 
> Best,
> Jordan
> 
> 
>> On Sep 15, 2017, at 15:47, Rex Fenley  wrote:
>> 
>> Hey Jordan,
>> 
>> Thank you for the time writing this up. I've been following along to the 
>> discussion somewhat closely and have kept silent because `exhaustive` was 
>> originally set to be the default for enums. However, that changed and so I'd 
>> like to voice my opinion, I frankly don't like this idea.
>> 
>> At remind we use algebraic data types religiously for managing state and 
>> data and rely on exhaustive pattern matching to guarantee we're handling all 
>> states in our code. We're splitting out our code across modules and having 
>> this guarantee has been a joy to work with.
>> 
>> The benefit of making nonexhaustive the default for Swift 5 across all 
>> multi-module code (besides C code) seems minimal to me. If a developer feels 
>> like they're unnecessarily managing enum cases, they can simply add a 
>> `default` case whenever they please. This is already the case and I'm 
>> curious if there's every been any complaints about this and what they would 
>> be. I'd prefer to be cautious and force exhaustive pattern matching in all 
>> possible cases and leave it up to the developer to choose not to.
>> 
>> Ideally in my mind, these keywords won't be necessary. All Swift enums will 
>> remain as they are, exhaustively pattern matched by default. Enums from C 
>> code will be explicitly nonexhaustive in all cases.
>> 
>> -- 
>> Rex Fenley  |  IOS DEVELOPER
>> 
>> 
>> Remind.com |  BLOG  |  FOLLOW US  |  LIKE US
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-15 Thread Jon Shier via swift-evolution
In that case Jordan, can Swift not treat it like open? i.e. Internally 
to a module, unmarked enums are still exhaustive by default, but when made 
public and used beyond the module, it becomes non-exhaustive? I think this has 
been discussed before and perhaps discarded as confusing, but it doesn’t seem 
to be any more confusing than open being the default internally and closed the 
default publicly. Otherwise you’re essentially forcing what is likely the vast 
majority of enum usage to adopt a bit of boilerplate that will only be used by 
the vast minority of libraries (almost entirely libraries shipped by Apple). 


Jon

> On Sep 15, 2017, at 8:07 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> Hi, Rex. I definitely agree that 'exhaustive' is the right model for a 
> multi-module app; indeed, there's no real reason for a single project to do 
> anything else. However, it is not always the right behavior for libraries 
> that actually get distributed, whether as source or as binary. In this case 
> we want to minimize the error of omission: in the app case, forgetting 
> "exhaustive" is an annoyance that you notice and fix once across your code 
> base, but in the library case forgetting the "default case" means putting out 
> a source-breaking release, and for libraries that have binary compatibility 
> constraints there's no recourse at all.
> 
> While most of the proposal deals with the experience we've had with the Apple 
> SDKs (as written in Objective-C), we actually have run into this case in 
> Swift already. The Swift Playgrounds app comes with a framework, 
> PlaygroundSupport, that can be used from within a playground. It's important 
> that when they upgrade the app, existing playgrounds don't break, since the 
> end user may not have access to the entire code of the playground. (Remember 
> that playgrounds are often authored by one developer or group, but then run 
> and modified by someone else with a much lower skill level!) That means that 
> PlaygroundSupport can't currently vend any enums that they expect playground 
> authors to exhaustively switch over.
> 
> (And to make it even more specific—and appealing—one of the enums they were 
> considering would be a representation of the Swift AST. This can obviously 
> change from release to release, but previous switch statements should stay 
> valid.)
> 
> Now, this is an example we know about, so we could certainly make it 
> explicitly non-exhaustive. But in general we're in the same situation as 
> 'open': if we want to be friendly to library authors, we need to make the 
> default thing be the one that promises less, even if it means a bit of extra 
> work in the "I-actually-own-everything" case.
> 
> Best,
> Jordan
> 
> 
>> On Sep 15, 2017, at 15:47, Rex Fenley > > wrote:
>> 
>> Hey Jordan,
>> 
>> Thank you for the time writing this up. I've been following along to the 
>> discussion somewhat closely and have kept silent because `exhaustive` was 
>> originally set to be the default for enums. However, that changed and so I'd 
>> like to voice my opinion, I frankly don't like this idea.
>> 
>> At remind we use algebraic data types religiously for managing state and 
>> data and rely on exhaustive pattern matching to guarantee we're handling all 
>> states in our code. We're splitting out our code across modules and having 
>> this guarantee has been a joy to work with.
>> 
>> The benefit of making nonexhaustive the default for Swift 5 across all 
>> multi-module code (besides C code) seems minimal to me. If a developer feels 
>> like they're unnecessarily managing enum cases, they can simply add a 
>> `default` case whenever they please. This is already the case and I'm 
>> curious if there's every been any complaints about this and what they would 
>> be. I'd prefer to be cautious and force exhaustive pattern matching in all 
>> possible cases and leave it up to the developer to choose not to.
>> 
>> Ideally in my mind, these keywords won't be necessary. All Swift enums will 
>> remain as they are, exhaustively pattern matched by default. Enums from C 
>> code will be explicitly nonexhaustive in all cases.
>> 
>> -- 
>> Rex Fenley  |  IOS DEVELOPER
>> 
>> 
>> Remind.com  |  BLOG   |  
>> FOLLOW US   |  LIKE US 
>> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-15 Thread Jordan Rose via swift-evolution
Hi, Rex. I definitely agree that 'exhaustive' is the right model for a 
multi-module app; indeed, there's no real reason for a single project to do 
anything else. However, it is not always the right behavior for libraries that 
actually get distributed, whether as source or as binary. In this case we want 
to minimize the error of omission: in the app case, forgetting "exhaustive" is 
an annoyance that you notice and fix once across your code base, but in the 
library case forgetting the "default case" means putting out a source-breaking 
release, and for libraries that have binary compatibility constraints there's 
no recourse at all.

While most of the proposal deals with the experience we've had with the Apple 
SDKs (as written in Objective-C), we actually have run into this case in Swift 
already. The Swift Playgrounds app comes with a framework, PlaygroundSupport, 
that can be used from within a playground. It's important that when they 
upgrade the app, existing playgrounds don't break, since the end user may not 
have access to the entire code of the playground. (Remember that playgrounds 
are often authored by one developer or group, but then run and modified by 
someone else with a much lower skill level!) That means that PlaygroundSupport 
can't currently vend any enums that they expect playground authors to 
exhaustively switch over.

(And to make it even more specific—and appealing—one of the enums they were 
considering would be a representation of the Swift AST. This can obviously 
change from release to release, but previous switch statements should stay 
valid.)

Now, this is an example we know about, so we could certainly make it explicitly 
non-exhaustive. But in general we're in the same situation as 'open': if we 
want to be friendly to library authors, we need to make the default thing be 
the one that promises less, even if it means a bit of extra work in the 
"I-actually-own-everything" case.

Best,
Jordan


> On Sep 15, 2017, at 15:47, Rex Fenley  wrote:
> 
> Hey Jordan,
> 
> Thank you for the time writing this up. I've been following along to the 
> discussion somewhat closely and have kept silent because `exhaustive` was 
> originally set to be the default for enums. However, that changed and so I'd 
> like to voice my opinion, I frankly don't like this idea.
> 
> At remind we use algebraic data types religiously for managing state and data 
> and rely on exhaustive pattern matching to guarantee we're handling all 
> states in our code. We're splitting out our code across modules and having 
> this guarantee has been a joy to work with.
> 
> The benefit of making nonexhaustive the default for Swift 5 across all 
> multi-module code (besides C code) seems minimal to me. If a developer feels 
> like they're unnecessarily managing enum cases, they can simply add a 
> `default` case whenever they please. This is already the case and I'm curious 
> if there's every been any complaints about this and what they would be. I'd 
> prefer to be cautious and force exhaustive pattern matching in all possible 
> cases and leave it up to the developer to choose not to.
> 
> Ideally in my mind, these keywords won't be necessary. All Swift enums will 
> remain as they are, exhaustively pattern matched by default. Enums from C 
> code will be explicitly nonexhaustive in all cases.
> 
> -- 
> Rex Fenley  |  IOS DEVELOPER
> 
> 
> Remind.com  |  BLOG   |  
> FOLLOW US   |  LIKE US 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-15 Thread Jordan Rose via swift-evolution


> On Sep 14, 2017, at 20:59, Chris Lattner  wrote:
> 
> 
>> On Sep 13, 2017, at 12:17 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> Proposal updated, same URL: 
>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>  
>> .
>> 
>> Thanks again for all the feedback so far, everyone!
> 
> Hi Jordan,
> 
> I’d appreciate it if you could look at the comments I made upthread and 
> respond to them.  Thanks.

Hi, Chris. Sorry for not responding directly – I assumed because your model was 
very close to this revised proposal, you wouldn't be expecting a direct 
response. At this point, I think the only discrepancy between your version and 
mine is that you'd use a shared annotation 'fragile' (or whatever) rather than 
an enum-specific annotation 'exhaustive' (or whatever). There are a few reasons 
why I didn't go with that:

- Unlike the other possible "fragility attributes" described in the Library 
Evolution  plan, 
'exhaustive' changes the behavior of the type in a way that's visible to 
clients. Stating that a struct has a fixed set of stored properties, or that a 
function's definition can be inlined into a caller, acts purely as an 
optimization; it doesn't change what client source code can or cannot do with a 
type.

- Because exhaustivity affects clients, it's something that is useful for 
libraries distributed as source* as well as those with binary-compatibility 
concerns. If such a library provides an exhaustive enum in its public API, 
adding a new case would be a source-breaking change and require a major version 
bump (if the library is using semantic versioning ). 
Therefore, just like open and non-open classes, it is beneficial to distinguish 
between the exhaustive and non-exhaustive situations even for libraries 
distributed as source. Such libraries should have no need for the other 
fragility attributes because we expect to be able to perform those 
optimizations by default.

I really wish 'open' made sense here, because that's the closest analogous 
situation, but it just doesn't. So we need a separate annotation (although as 
mentioned in the proposal I'm okay with reusing 'final').

It does help now that `public enum` works without any further annotation; 
that's due to your feedback as well as pushes within Apple.

Jordan


* I'm saying "libraries distributed as source", but really this applies to any 
libraries that get packaged with the end product, usually an app. The real 
condition here is whether a client must be rebuilt to use a new version of the 
library, i.e. "libraries without binary compatibility concerns". These aren't 
officially supported by Apple today, but the model shouldn't leave them out.

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-13 Thread Rod Brown via swift-evolution
Hi Jordan,

I think this is a great update to the proposal. The scope is small, which is 
good, and it clearly speaks about it’s reasoning about some of the concerns 
some people have.

A big thumbs up from me! 

- Rod

> On 14 Sep 2017, at 5:16 am, Jordan Rose via swift-evolution 
>  wrote:
> 
> Proposal updated, same URL: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md.
> 
> Thanks again for all the feedback so far, everyone!
> Jordan
> 
> 
>> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
>>  wrote:
>> 
>> Sorry, I got distracted by other tasks! Both the discussion here and within 
>> Apple has moved towards making "non-exhaustive" the default, which, to be 
>> honest, I too think is the best design. I'll update the proposal today to 
>> reflect that, though I still want to keep both the "nonexhaustive" and 
>> "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end 
>> up naming them). The compatibility design is a little less ambitious than 
>> Brent's; as currently proposed, Swift 4 mode continues to default to 
>> 'exhaustive' all the time, even in the actual Swift 5 release.
>> 
>> I still want to respond to Brent's points directly, but I think you and 
>> Vladimir have done a good job discussing them already. I'll send out the 
>> updated proposal tomorrow, after I have a little more time to think about 
>> #invalid.
>> 
>> Thanks for putting time into this!
>> Jordan
>> 
>> 
>>> On Sep 9, 2017, at 17:34, Rod Brown  wrote:
>>> 
>>> Jordan,
>>> 
>>> Do you have any other thoughts about the ongoing discussion here, 
>>> especially regarding Chris’ comments? As you’re the one pushing this 
>>> forward, I’d really like to know what your thoughts are regarding this?
>>> 
>>> - Rod
>> 
>> ___
>> 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
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-13 Thread Jordan Rose via swift-evolution
Proposal updated, same URL: 
https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
 
.

Thanks again for all the feedback so far, everyone!
Jordan


> On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution 
>  wrote:
> 
> Sorry, I got distracted by other tasks! Both the discussion here and within 
> Apple has moved towards making "non-exhaustive" the default, which, to be 
> honest, I too think is the best design. I'll update the proposal today to 
> reflect that, though I still want to keep both the "nonexhaustive" and 
> "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end 
> up naming them). The compatibility design is a little less ambitious than 
> Brent's; as currently proposed, Swift 4 mode continues to default to 
> 'exhaustive' all the time, even in the actual Swift 5 release.
> 
> I still want to respond to Brent's points directly, but I think you and 
> Vladimir have done a good job discussing them already. I'll send out the 
> updated proposal tomorrow, after I have a little more time to think about 
> #invalid.
> 
> Thanks for putting time into this!
> Jordan
> 
> 
>> On Sep 9, 2017, at 17:34, Rod Brown  wrote:
>> 
>> Jordan,
>> 
>> Do you have any other thoughts about the ongoing discussion here, especially 
>> regarding Chris’ comments? As you’re the one pushing this forward, I’d 
>> really like to know what your thoughts are regarding this?
>> 
>> - Rod
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-13 Thread Jordan Rose via swift-evolution

> On Sep 13, 2017, at 05:21, Brent Royal-Gordon  wrote:
> 
>> On Sep 12, 2017, at 6:30 PM, Jordan Rose > > wrote:
>> 
>> It gets a little tricky if layout matters—Optional fits exactly 
>> in a single word-sized value, but Optional does not on 
>> Apple platforms—but that just means it should be opt-in or tied to 
>> -enable-testing in some way.
> 
> 
> I forgot to state this explicitly, but I agree—unless the module was compiled 
> with -enable-testing, the generated code should not permit #invalid values 
> and would be identical to a version without any @testable parameters/types.
> 
> Here's a more explicit sketch of a design for this feature (albeit one that 
> has some impact on the type system and a couple weird corners):
> 
>   • `@testable T` is a supertype of `T` which, when the module is 
> compiled with `-enable-testing`, has an additional `#invalid` inhabitant. (We 
> can bikeshed `@testable` and `#invalid` some other time.) Notionally, 
> `@testable` is sort of like an enum which has one case (`valid(Wrapped)`) in 
> a non-`-enable-testing` build, and an additional case (`invalid`) in an 
> `-enable-testing` build.
> 
>   • `T` implicitly converts to `@testable T`; `@testable T` can be 
> explicitly downcast to `T`.* When `-enable-testing` is *not* provided, these 
> downcasts will always succeed, and the trap in `as!` or the code for a `nil` 
> result from `as?` are unreachable. We should ignore and potentially optimize 
> away this unreachable code without warning about it.
> 
>   • Any pattern that matches against `T` can also match against 
> `@testable T` with no alteration. Only `_` or a capture can match 
> `#invalid`.** Otherwise, `#invalid` values will be handled by the `default` 
> case of a `switch` or the `else` block of an `if` or `guard`.
> 
>   • A given `@testable T` value (i.e. property, variable, subscript, 
> parameter, return value, etc.) may only be assigned `#invalid` if it is 
> either in the current module or is in a module imported with `@testable 
> import`.
> 
>   • When `-enable-testing` is *not* provided, all code which creates an 
> `#invalid` value must be unreachable. This is even true in `default:` cases 
> and other constructs which could be reached by unknown future values of a 
> type. Only constructs like `guard let t = testableT as? T else { return 
> #invalid }` can be successfully compiled with `-enable-testing` disabled.
> 
> The memory representation of `#invalid` does not have to be the same for all 
> types, so it could try to find a spare bit or bit pattern that's unused in 
> the original type (as long as, for non-exhaustive enums, it also avoids using 
> any bit pattern a future version of the type *might* use). Or, for 
> simplicity, we could just add a tag byte unconditionally. This tag byte would 
> only be needed when built with `-enable-testing`, so basically only debug 
> builds would pay this price, and only in places where the author explicitly 
> asked to be able to test with `#invalid` values.
> 
> 
> * There's an argument to be made for an IUO-style implicit conversion from 
> `@testable Foo` to `Foo` which traps on `#invalid`. This seems dangerous to 
> me, but on the other hand, you should only ever encounter it in testing or 
> development, never in production.
> 
> ** I'm not sure captures can work here—wouldn't they still be the `@testable` 
> type?—so I'm actually wondering if we should introduce a subtle distinction 
> between `case _`/`case let x` and `default`: the former cannot match 
> `#invalid`, while the latter can. That would be a little bit…odd, though.

Thanks for working this out. This matches the intuitions I was having, and also 
finds a point that’s pretty concerning:

> * There's an argument to be made for an IUO-style implicit conversion from 
> `@testable Foo` to `Foo` which traps on `#invalid`. This seems dangerous to 
> me, but on the other hand, you should only ever encounter it in testing or 
> development, never in production.

It’s going to be very common to have a future value and hand it right back to 
the framework without looking at it, for example:

override func process(_ transaction: @testable Transaction) {
  switch transaction {
  case .deposit(let amount):
// …
  case .withdrawal(let amount):
// …
  default:
super.process(transaction) // hmm…
  }
}

So just making it to the ‘default’ case doesn’t guarantee that it’s testable in 
practice.

In any case, a model like this can be added later without breaking source or 
binary compatibility, so I think I’m going to leave it out of the proposal for 
now. I’ll mention it in “Alternatives considered”.

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-13 Thread Brent Royal-Gordon via swift-evolution
> On Sep 12, 2017, at 6:30 PM, Jordan Rose  wrote:
> 
> It gets a little tricky if layout matters—Optional fits exactly in 
> a single word-sized value, but Optional does not on 
> Apple platforms—but that just means it should be opt-in or tied to 
> -enable-testing in some way.


I forgot to state this explicitly, but I agree—unless the module was compiled 
with -enable-testing, the generated code should not permit #invalid values and 
would be identical to a version without any @testable parameters/types.

Here's a more explicit sketch of a design for this feature (albeit one that has 
some impact on the type system and a couple weird corners):

• `@testable T` is a supertype of `T` which, when the module is 
compiled with `-enable-testing`, has an additional `#invalid` inhabitant. (We 
can bikeshed `@testable` and `#invalid` some other time.) Notionally, 
`@testable` is sort of like an enum which has one case (`valid(Wrapped)`) in a 
non-`-enable-testing` build, and an additional case (`invalid`) in an 
`-enable-testing` build.

• `T` implicitly converts to `@testable T`; `@testable T` can be 
explicitly downcast to `T`.* When `-enable-testing` is *not* provided, these 
downcasts will always succeed, and the trap in `as!` or the code for a `nil` 
result from `as?` are unreachable. We should ignore and potentially optimize 
away this unreachable code without warning about it.

• Any pattern that matches against `T` can also match against 
`@testable T` with no alteration. Only `_` or a capture can match `#invalid`.** 
Otherwise, `#invalid` values will be handled by the `default` case of a 
`switch` or the `else` block of an `if` or `guard`.

• A given `@testable T` value (i.e. property, variable, subscript, 
parameter, return value, etc.) may only be assigned `#invalid` if it is either 
in the current module or is in a module imported with `@testable import`.

• When `-enable-testing` is *not* provided, all code which creates an 
`#invalid` value must be unreachable. This is even true in `default:` cases and 
other constructs which could be reached by unknown future values of a type. 
Only constructs like `guard let t = testableT as? T else { return #invalid }` 
can be successfully compiled with `-enable-testing` disabled.

The memory representation of `#invalid` does not have to be the same for all 
types, so it could try to find a spare bit or bit pattern that's unused in the 
original type (as long as, for non-exhaustive enums, it also avoids using any 
bit pattern a future version of the type *might* use). Or, for simplicity, we 
could just add a tag byte unconditionally. This tag byte would only be needed 
when built with `-enable-testing`, so basically only debug builds would pay 
this price, and only in places where the author explicitly asked to be able to 
test with `#invalid` values.


* There's an argument to be made for an IUO-style implicit conversion from 
`@testable Foo` to `Foo` which traps on `#invalid`. This seems dangerous to me, 
but on the other hand, you should only ever encounter it in testing or 
development, never in production.

** I'm not sure captures can work here—wouldn't they still be the `@testable` 
type?—so I'm actually wondering if we should introduce a subtle distinction 
between `case _`/`case let x` and `default`: the former cannot match 
`#invalid`, while the latter can. That would be a little bit…odd, though.

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-12 Thread Jordan Rose via swift-evolution
Just getting around to this again. Thanks for putting a fair amount of thought 
in! I'm putting short section-by-section responses here, though the other 
discussion has already covered a fair amount. I'm planning to have a new 
revision of the proposal up tomorrow as well.


> On Sep 6, 2017, at 05:53, Brent Royal-Gordon  wrote:
> 
>> On Sep 5, 2017, at 5:19 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> I've taken everyone's feedback into consideration and written this up as a 
>> proposal: 
>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>  
>> .
>>  The next step is working on an implementation, but if people have further 
>> pre-review comments I'd be happy to hear them.
> 
> I disagree with the choice of `exhaustive` and `nonexhaustive`. They are too 
> long; the more resilient keyword is longer than the more fragile one (and 
> difficult to read!); and they don't match the clang annotation. We may have 
> to compromise on one or two of these, but the combination of all three ought 
> to be considered disqualifying.
> 
> I think `final`/`nonfinal`, `total`/`partial`, `fixed`/? or `permanent`/? are 
> all better because they're shorter, although they all have problems with 
> their antonyms. `candid`/`coy` or `candid`/`shy` produce the right soft 
> default, but are kind of weirdly figurative.

I'm very happy for the review to end up settling on something else. It also 
sounds like the direction to go in will make 'nonexhaustive' the default in 
Swift 5 mode, so it at least wins on the second criterion in the long run.


> 
> But I don't think a change of keywords will fix everything here. 
> Fundamentally, I am not convinced that source compatibility of `switch` 
> statements should be weighed so heavily. Based on your survey of Foundation, 
> you suggest that the vast majority of imported enums should source-break all 
> switches in Swift 5. Why is that acceptable, but making Swift enums 
> source-breaking unacceptable?

Good point! I think it's acceptable because people were unlikely to be 
exhaustively switching over imported enums anyway, on the grounds that most of 
them aren't just non-exhaustive but actually don't make any sense to switch 
over in the first place. On the other hand, breaking Swift enums (when not 
migrated) is something that could cause pain for a while, rather than just 
being a one-time "go fix all the compiler issues". But you all are convincing 
me it's not as big a deal as I thought.


> 
> I suspect that, in practice, `public` enums tend to fall into two categories:
> 
>   1. "Data enums" which represent important data that happens to consist 
> of a set of alternatives. Outside users will frequently need to switch over 
> these, but they are not very likely to evolve or have private cases.
> 
>   2. "Mode enums" which tweak the behavior of an API. These are very 
> likely to evolve or have private cases, but outside users are not very likely 
> to need to switch over them.
> 
> An example of a data enum would be, as you mentioned, `NSComparisonResult`. 
> People really *do* need to be able to test against it, but barring some 
> fundamental break in the nature of reality, it will only ever have those 
> three cases. So it's fine to make it exhaustive.
> 
> An example of a mode enum would be `UIViewAnimationCurve`, which tells UIKit 
> how to ease an animation. I chose that example because I actually traced a 
> bug just last week to my mistaken impression that this enum had no private 
> cases. I was mapping values of this type to their corresponding 
> `UIViewAnimationOptions` values; because there were private cases, this was 
> Objective-C code, and I didn't include sufficiently aggressive assertions, I 
> ended up reading garbage data from memory. But while debugging this, it 
> struck me that this was actually *really weird* code. How often do you, as a 
> developer outside UIKit, need to interpret the value of a type like 
> `UIViewAnimationCurve`? If the compiler suddenly changed the exhaustiveness 
> behavior of `UIViewAnimationCurve`, probably less than 1% of apps would even 
> notice—and the affected code would probably have latent bugs!
> 
> Here's my point: Suddenly treating a mode enum as non-exhaustive is 
> *technically* source-breaking, but *people aren't doing things to them that 
> would break*. It is only the data enums that would actually experience source 
> breakage, and we both seem to agree those are relatively uncommon. So I would 
> argue the relatively rare source breaks are acceptable.

That's the hope! And still only when you're ready to migrate to Swift 5 mode.

> 
> Basically, what I would suggest is this:
> 
>   1. In Swift 4.1, we should add a permanent 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-12 Thread Jordan Rose via swift-evolution
Sorry, I got distracted by other tasks! Both the discussion here and within 
Apple has moved towards making "non-exhaustive" the default, which, to be 
honest, I too think is the best design. I'll update the proposal today to 
reflect that, though I still want to keep both the "nonexhaustive" and 
"exhaustive" keywords for Swift 4 compatibility for now (or whatever we end up 
naming them). The compatibility design is a little less ambitious than Brent's; 
as currently proposed, Swift 4 mode continues to default to 'exhaustive' all 
the time, even in the actual Swift 5 release.

I still want to respond to Brent's points directly, but I think you and 
Vladimir have done a good job discussing them already. I'll send out the 
updated proposal tomorrow, after I have a little more time to think about 
#invalid.

Thanks for putting time into this!
Jordan


> On Sep 9, 2017, at 17:34, Rod Brown  wrote:
> 
> Jordan,
> 
> Do you have any other thoughts about the ongoing discussion here, especially 
> regarding Chris’ comments? As you’re the one pushing this forward, I’d really 
> like to know what your thoughts are regarding this?
> 
> - Rod

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-12 Thread Jordan Rose via swift-evolution
I don't think RawRepresentable really has anything to do with this. Enums with 
payloads often don't have any particular reasonable raw values.

We could certainly spell non-exhaustive enums as "enum struct", but I don't 
think that'll be more obvious to other people than any of the names that have 
already been proposed.

Jordan


> On Sep 6, 2017, at 11:05, Jose Cheyo Jimenez  wrote:
> 
> Here is an alternative view. I've been thinking about this and I feel that 
> instead of adding this to an enum why not make RawRepresentable structs a 
> swift construct. 
> 
> You could declare it like this:
> 
> enum struct {
>case a, b, c
> }
> 
> This would be a struct that acts like an enum but it is open like a 
> RawRepresentable but using the enum case sugar. 
> 
> On Sep 5, 2017, at 5:37 PM, Jordan Rose via swift-evolution 
> > wrote:
> 
>> It's in the "Alternatives Considered" section. :-) That was my desired 
>> design when we started, but feedback convinced me that the break from Swift 
>> 4 mode would be too drastic. The same valid code would have a different 
>> meaning whether you were writing Swift 4 or Swift 5.
>> 
>> Jordan
>> 
>> 
>>> On Sep 5, 2017, at 17:30, Rod Brown >> > wrote:
>>> 
>>> Hi Jordan,
>>> 
>>> I’m not sure how much bearing on this my comment will have.
>>> 
>>> Have you considered having only “exhaustive” as a keyword, and make the 
>>> default non-exhaustive? It seems that “exhaustive" would be the rarer case, 
>>> as it promises a lot more about compatibility (much like there is no such 
>>> thing as “non-final”). Also, non exhaustive seems a massive mouthful 
>>> despite it probably being the correct term.
>>> 
>>> - Rod
>>> 
 On 6 Sep 2017, at 10:19 am, Jordan Rose > wrote:
 
 I've taken everyone's feedback into consideration and written this up as a 
 proposal: 
 https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
  
 .
  The next step is working on an implementation, but if people have further 
 pre-review comments I'd be happy to hear them.
 
 Jordan
>> 
>> ___
>> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-09 Thread Chris Lattner via swift-evolution

> On Sep 6, 2017, at 10:37 PM, Rod Brown  wrote:
> 
>> We’ve talked about enums many times across years, and it seems like the 
>> appropriate model follows the generally understood resilience model.  
>> Specifically, there should be three different kinds of enums, and the kind 
>> should affect users outside their module in different ways:
>> 
>> 1. private/fileprivate/internal enum: cases can be added freely.  All 
>> clients are in the same module, so the enum is implicitly fragile, and all 
>> switches within the current module may therefore be exhaustive.
>> 
>> 2. public enum (i.e., one that isn’t marked fragile): cases may be added 
>> freely.  Within the module that defines the enum, switches may be 
>> exhaustive.  However, because the enum is public and non-fragile, clients 
>> outside the current module must be prepared for the enum to add additional 
>> cases in future revisions of the API, and therefore they cannot exhaustively 
>> match the cases of the enum.
>> 
>> 3. fragile public enum: cases may not be added, because that would break the 
>> fragility guarantee.  As such, clients within or outside of hte current 
>> module may exhaustively match against the enum.
>> 
>> 
>> This approach gives a very natural user model: app developers don’t have to 
>> care about enum resilience until they mark an enum as public, and even then 
>> they only have to care about it when/if they mark an enum as public.  This 
>> also builds on the notion of fragility - something we need for other nominal 
>> types like structs and classes - so it doesn’t introduce new language 
>> complexity.  Also such an approach is entirely source compatible with Swift 
>> 3/4, which require defaults (this isn’t an accident, it follows from the 
>> anticipated design).
>> 
>> This approach doesn’t address the problem of what to do with C though, 
>> because C doesn’t have a reasonable notion of “extensible” vs 
>> “nonextensible” enum.  As such, we definitely do need an attribute (or 
>> something) to add to Clang.  I think that your proposal for defaulting to 
>> “extensible” and using __attribute__((enum_extensibility(closed))) override 
>> this is perfectly sensible.
>> 
>> -Chris
>> 
> 
> Hi Chris,
> 
> I think I agree with you in general, with 1 exception:
> 
> I think the wording “fragile”, while technically correct, implies the exact 
> opposite of the promise contract, namely that it will not change between 
> releases of your framework. Perhaps a term like “concrete” would be more 
> appropriate? It would be fragile in that it is a fragile interface, but it 
> would be concrete as a promise to external dependencies. If you are 
> exhaustively enumerating, you’re basing it on the notion that it won’t 
> change, not that it’s "easy to break” (which fragile as a word would seem to 
> imply).

Hi Rod,

Just to clarify, I wasn’t intending to make a syntax proposal here.  I was 
talking about the semantic model that we should provide.  The bikeshed should 
be painted in a color that aligns best with the rest of the resilience model.

-Chris

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-09 Thread Rod Brown via swift-evolution
Jordan,

Do you have any other thoughts about the ongoing discussion here, especially 
regarding Chris’ comments? As you’re the one pushing this forward, I’d really 
like to know what your thoughts are regarding this?

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-07 Thread Rod Brown via swift-evolution


> On 8 Sep 2017, at 2:55 am, Vladimir.S  wrote:
> 
> On 07.09.2017 18:23, Rod Brown wrote:
>> 
>> This was discussed earlier. As I mentioned, we should be realistic: it’s 
>> rarely a
>> truly fatal error when you get an unknown enum. Unless you really can’t find 
>> a
>> reasonable default, then there are almost always reasonable logical ways to 
>> handle
>> it (perhaps just breaking out?). And in cases where you really need to 
>> handle each
>> case, this would (almost?) always be an exhaustive enum. I can’t even 
>> imagine the
>> case where it would be so critical you couldn’t handle it with reasonable 
>> control
>> flow. There are always solutions like returning early, breaking out, default
>> details. I see Swift code littered with fatalError() not because its needed, 
>> but
>> because the developer often didn’t care enough to think it through.
> 
> Thank you for replies, Rod!
> 
> Thinking about this, if "in cases where you really need to handle each case, 
> this would (almost?) always be an exhaustive enum", then I tend to agree with 
> you.
> 
> So, currently my point of view is that we need to move the way suggested by 
> Chris, when we need to mark public 'closed' enum, so 'open' is default, and 
> with warning for first time and with error in next version of Swift for 
> switches on 'open' enum without 'default' case. Not the way described in the 
> proposal itself.

Agreed, though we shouldn't use “open/closed” as discussed in the proposal 
draft.

> 
>> “Future” might be a decent idea, but I think we’re overcomplicating it. Just 
>> use
>> “default” as we always have? “Future” as a word doesn’t seem to apply, as I 
>> have
>> mentioned earlier: there are cases where your framework has a private case 
>> on an
>> enum. This isn’t necessarily a future case - it could be “current”. If we 
>> were to
>> do this, it would make more sense to call this case word “other” instead. 
>> Again,
>> though, we’re adding complexity to a switch for a very rare case and a 
>> little bit
>> of developer convenience in that case.
> 
> Well... yes, seems like this. I didn't get current but private cases into 
> account. But I was more focused on Swift's enums, not on C's.
> 
> What do you(and others) think about such idea: if we have an exhaustive 
> switch on _open_ enum _without_ 'default' case, and there are *no* more known 
> available cases for this enum currently - compiler generates error/warning 
> like "you have exhaustive switch but this is an open enum new cases can be 
> added later, so add 'default' case to process them". But, if such(exhaustive 
> on _open_ enum _without_ 'default' case) switch contains not all known cases, 
> warning/error will be different like "you have not exhaustive switch on open 
> enum, add 'default' case to process all others and future cases”.

I agree. This is going to be a confusing case, especially when transitioning. 
Stating clearly why they need a default clause despite the “appearance” of 
exhaustively handling all cases should be part of the error wording.

> 
> I believe that with this accepted proposal, if you ever will need to keep 
> switch exhaustive on 'open' enum, support this code, this will be a nightmare 
> without at least such warnings, when you can comment the 'default' case in 
> switch and check(by warning/error message) if you processed all the cases or 
> missed some. Otherwise, the alternative, is to manually check one-by-one what 
> you have in your switch and what cases are in enum(in case you have new 
> version of enum's module).
> 
> Vladimir.
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-07 Thread Vladimir.S via swift-evolution

On 07.09.2017 18:23, Rod Brown wrote:




On 8 Sep 2017, at 12:24 am, Vladimir.S  wrote:



On 07.09.2017 16:03, Rod Brown wrote:

On 7 Sep 2017, at 9:26 pm, Vladimir.S via swift-evolution
> wrote: Just
small note. As I understand, this is a source breaking suggestion, no? I
mean any client code for 'public enum' coming from another module, will have
to add 'default' case in 'switch'. So, the previously correct code will not
compile. Or do you suggest to raise a warning only for the first time and
raise an error in next version of Swift?

Yes. By defaulting to “non fragile” we add a source incompatibility, because
Swift is currently assuming fragility. In Jordan’s proposal, it is assuming
fragility/exhaustive by default, and therefore would be source compatible.
Good point. I keep wavering back and forth on the importance of Source
Compatibility with this one. Defaulting to “exhaustive” seems dangerous to me.
It makes your framework (and future versions of it) fragile without ever
having to think about it. At least if the keyword of “exhaustive” or “fragile”
or “sealed” meant that you actively chose the fragility that will handcuff you
later down the road.


Yes, probably(still thinking about this) I agree that 'open'('exhaustive') enum
should be the default for public enum; and only if author is really sure enum
will not change in future and to provide a space for compiler's optimizations
and suggest client to switch exhaustive, he/she can mark such enum as
exhaustive/fragile/sealed/closed/fixed. And seems like the right direction is
raise warnings fist, and errors in next version of Swift.

The only question I can't find strong answer for, what my code(as a client of
'open' enum) will do in 'default' case? Will it be in 95% cases the
fatalError().. If so, what is the difference with current situation? If my
switch is already exhaustive regarding some public(imported) enum, so I'm
processing all the possible *at the compilation time* cases - most likely I'll
have just fatalError() in 'default'. If my switch already contains 'default' -
the proposed change will not affect me at all…


This was discussed earlier. As I mentioned, we should be realistic: it’s rarely 
a
truly fatal error when you get an unknown enum. Unless you really can’t find a
reasonable default, then there are almost always reasonable logical ways to 
handle
it (perhaps just breaking out?). And in cases where you really need to handle 
each
case, this would (almost?) always be an exhaustive enum. I can’t even imagine 
the
case where it would be so critical you couldn’t handle it with reasonable 
control
flow. There are always solutions like returning early, breaking out, default
details. I see Swift code littered with fatalError() not because its needed, but
because the developer often didn’t care enough to think it through.



Thank you for replies, Rod!

Thinking about this, if "in cases where you really need to handle each case, this 
would (almost?) always be an exhaustive enum", then I tend to agree with you.


So, currently my point of view is that we need to move the way suggested by Chris, 
when we need to mark public 'closed' enum, so 'open' is default, and with warning for 
first time and with error in next version of Swift for switches on 'open' enum 
without 'default' case. Not the way described in the proposal itself.




But probably it is better to have a choice what to do with future cases, than
have just one direction - crash at run time if new case in external enum is
added.

But the same I can say for proposed 'future' case : it is better to have a
choice what to use - 'default', if we don't need to be exhaustive on 'open'
enum,  or 'future', if we need to be exhaustive on 'open' enum in compile-time
but separately process all future cases.


“Future” might be a decent idea, but I think we’re overcomplicating it. Just use
“default” as we always have? “Future” as a word doesn’t seem to apply, as I have
mentioned earlier: there are cases where your framework has a private case on an
enum. This isn’t necessarily a future case - it could be “current”. If we were 
to
do this, it would make more sense to call this case word “other” instead. Again,
though, we’re adding complexity to a switch for a very rare case and a little 
bit
of developer convenience in that case.


Well... yes, seems like this. I didn't get current but private cases into account. 
But I was more focused on Swift's enums, not on C's.


What do you(and others) think about such idea: if we have an exhaustive switch on 
_open_ enum _without_ 'default' case, and there are *no* more known available cases 
for this enum currently - compiler generates error/warning like "you have exhaustive 
switch but this is an open enum new cases can be added later, so add 'default' case 
to process them". But, if such(exhaustive on _open_ enum _without_ 'default' case) 
switch contains not all 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-07 Thread Rod Brown via swift-evolution


> On 8 Sep 2017, at 12:24 am, Vladimir.S  wrote:
> 
> 
> 
> On 07.09.2017 16:03, Rod Brown wrote:
>>> On 7 Sep 2017, at 9:26 pm, Vladimir.S via swift-evolution 
>>> > wrote:
>>> Just small note. As I understand, this is a source breaking suggestion, no?
>>> I mean any client code for 'public enum' coming from another module, will 
>>> have to add 'default' case in 'switch'. So, the previously correct code 
>>> will not compile. Or do you suggest to raise a warning only for the first 
>>> time and raise an error in next version of Swift?
>> Yes. By defaulting to “non fragile” we add a source incompatibility, because 
>> Swift is currently assuming fragility. In Jordan’s proposal, it is assuming 
>> fragility/exhaustive by default, and therefore would be source compatible. 
>> Good point.
>> I keep wavering back and forth on the importance of Source Compatibility 
>> with this one. Defaulting to “exhaustive” seems dangerous to me. It makes 
>> your framework (and future versions of it) fragile without ever having to 
>> think about it. At least if the keyword of “exhaustive” or “fragile” or 
>> “sealed” meant that you actively chose the fragility that will handcuff you 
>> later down the road.
> 
> Yes, probably(still thinking about this) I agree that 'open'('exhaustive') 
> enum should be the default for public enum; and only if author is really sure 
> enum will not change in future and to provide a space for compiler's 
> optimizations and suggest client to switch exhaustive, he/she can mark such 
> enum as exhaustive/fragile/sealed/closed/fixed. And seems like the right 
> direction is raise warnings fist, and errors in next version of Swift.
> 
> The only question I can't find strong answer for, what my code(as a client of 
> 'open' enum) will do in 'default' case? Will it be in 95% cases the 
> fatalError().. If so, what is the difference with current situation?
> If my switch is already exhaustive regarding some public(imported) enum, so 
> I'm processing all the possible *at the compilation time* cases - most likely 
> I'll have just fatalError() in 'default'.
> If my switch already contains 'default' - the proposed change will not affect 
> me at all…

This was discussed earlier. As I mentioned, we should be realistic: it’s rarely 
a truly fatal error when you get an unknown enum. Unless you really can’t find 
a reasonable default, then there are almost always reasonable logical ways to 
handle it (perhaps just breaking out?). And in cases where you really need to 
handle each case, this would (almost?) always be an exhaustive enum. I can’t 
even imagine the case where it would be so critical you couldn’t handle it with 
reasonable control flow. There are always solutions like returning early, 
breaking out, default details. I see Swift code littered with fatalError() not 
because its needed, but because the developer often didn’t care enough to think 
it through.

> 
> But probably it is better to have a choice what to do with future cases, than 
> have just one direction - crash at run time if new case in external enum is 
> added.
> 
> But the same I can say for proposed 'future' case : it is better to have a 
> choice what to use - 'default', if we don't need to be exhaustive on 'open' 
> enum,  or 'future', if we need to be exhaustive on 'open' enum in 
> compile-time but separately process all future cases.

“Future” might be a decent idea, but I think we’re overcomplicating it. Just 
use “default” as we always have? “Future” as a word doesn’t seem to apply, as I 
have mentioned earlier: there are cases where your framework has a private case 
on an enum. This isn’t necessarily a future case - it could be “current”. If we 
were to do this, it would make more sense to call this case word “other” 
instead. Again, though, we’re adding complexity to a switch for a very rare 
case and a little bit of developer convenience in that case.

> 
> Yes, in this case we have a problem with testability, but the same is true 
> for exhaustive switch with 'defailt' case - how this 'default' code can be 
> tested? Probably, we need to provide a solution for this in any case, not 
> because of 'future' but also for 'default' in exhaustive switch on 'open' 
> enum. (Don't know how this could be implemented, probably by somehow be able 
> to extend the imported open enum with 'fake' case when compile in special 
> mode for testing and be able to send this fake case into tested code)

Yes, testing this is a concern. I agree: have an ability to add an “other" case 
in tests.

> 
> Vladimir.
> 
>>> 
 3. fragile public enum: cases may not be added, because that would break 
 the fragility guarantee.  As such, clients within or outside of hte 
 current module may exhaustively match against the enum.
>>> 
>>> I think 'fragile' word does not reflect what is guaranteed for this enum. 
>>> The author guaranteed that this enum 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-07 Thread Vladimir.S via swift-evolution



On 07.09.2017 16:03, Rod Brown wrote:



On 7 Sep 2017, at 9:26 pm, Vladimir.S via swift-evolution 
> wrote:


On 07.09.2017 7:33, Chris Lattner via swift-evolution wrote:
On Sep 5, 2017, at 5:19 PM, Jordan Rose via swift-evolution 
 
> wrote:


I've taken everyone's feedback into consideration and written this up as a 
proposal: 
https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md. 
The next step is working on an implementation, but if people have further 
pre-review comments I'd be happy to hear them.

Hi Jordan,
I apologize in advance that I haven’t followed the back and forth on this thread, 
so I’m sorry if these thoughts are duplicative:
I really would prefer to avoid introducing the notion of exhaustive/nonexhaustive 
enums into Swift, and would much prefer that such a thing be limited to C (which 
can’t express this concept already).
We’ve talked about enums many times across years, and it seems like the 
appropriate model follows the generally understood resilience model. Specifically, 
there should be three different kinds of enums, and the kind should affect users 
outside their module in different ways:
1. private/fileprivate/internal enum: cases can be added freely.  All clients are 
in the same module, so the enum is implicitly fragile, and all switches within the 
current module may therefore be exhaustive.
2. public enum (i.e., one that isn’t marked fragile): cases may be added freely.   
Within the module that defines the enum, switches may be exhaustive.  However, 
because the enum is public and non-fragile, clients outside the current module 
must be prepared for the enum to add additional cases in future revisions of the 
API, and therefore they cannot exhaustively match the cases of the enum.


Just small note. As I understand, this is a source breaking suggestion, no?
I mean any client code for 'public enum' coming from another module, will have to 
add 'default' case in 'switch'. So, the previously correct code will not compile. 
Or do you suggest to raise a warning only for the first time and raise an error in 
next version of Swift?


Yes. By defaulting to “non fragile” we add a source incompatibility, because Swift is 
currently assuming fragility. In Jordan’s proposal, it is assuming 
fragility/exhaustive by default, and therefore would be source compatible. Good point.


I keep wavering back and forth on the importance of Source Compatibility with this 
one. Defaulting to “exhaustive” seems dangerous to me. It makes your framework (and 
future versions of it) fragile without ever having to think about it. At least if the 
keyword of “exhaustive” or “fragile” or “sealed” meant that you actively chose the 
fragility that will handcuff you later down the road.




Yes, probably(still thinking about this) I agree that 'open'('exhaustive') enum 
should be the default for public enum; and only if author is really sure enum will 
not change in future and to provide a space for compiler's optimizations and suggest 
client to switch exhaustive, he/she can mark such enum as 
exhaustive/fragile/sealed/closed/fixed. And seems like the right direction is raise 
warnings fist, and errors in next version of Swift.


The only question I can't find strong answer for, what my code(as a client of 'open' 
enum) will do in 'default' case? Will it be in 95% cases the fatalError().. If so, 
what is the difference with current situation?
If my switch is already exhaustive regarding some public(imported) enum, so I'm 
processing all the possible *at the compilation time* cases - most likely I'll have 
just fatalError() in 'default'.
If my switch already contains 'default' - the proposed change will not affect me at 
all...


But probably it is better to have a choice what to do with future cases, than have 
just one direction - crash at run time if new case in external enum is added.


But the same I can say for proposed 'future' case : it is better to have a choice 
what to use - 'default', if we don't need to be exhaustive on 'open' enum,  or 
'future', if we need to be exhaustive on 'open' enum in compile-time but separately 
process all future cases.


Yes, in this case we have a problem with testability, but the same is true for 
exhaustive switch with 'defailt' case - how this 'default' code can be tested? 
Probably, we need to provide a solution for this in any case, not because of 'future' 
but also for 'default' in exhaustive switch on 'open' enum. (Don't know how this 
could be implemented, probably by somehow be able to extend the imported open enum 
with 'fake' case when compile in special mode for testing and be able to send this 
fake case into tested code)


Vladimir.



3. fragile public enum: cases may not be added, because that would break the 
fragility guarantee.  As 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-07 Thread Rod Brown via swift-evolution


> On 7 Sep 2017, at 9:26 pm, Vladimir.S via swift-evolution 
>  wrote:
> 
> On 07.09.2017 7:33, Chris Lattner via swift-evolution wrote:
>>> On Sep 5, 2017, at 5:19 PM, Jordan Rose via swift-evolution 
>>> > wrote:
>>> 
>>> I've taken everyone's feedback into consideration and written this up as a 
>>> proposal: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md.
>>>  The next step is working on an implementation, but if people have further 
>>> pre-review comments I'd be happy to hear them.
>> Hi Jordan,
>> I apologize in advance that I haven’t followed the back and forth on this 
>> thread, so I’m sorry if these thoughts are duplicative:
>> I really would prefer to avoid introducing the notion of 
>> exhaustive/nonexhaustive enums into Swift, and would much prefer that such a 
>> thing be limited to C (which can’t express this concept already).
>> We’ve talked about enums many times across years, and it seems like the 
>> appropriate model follows the generally understood resilience model. 
>> Specifically, there should be three different kinds of enums, and the kind 
>> should affect users outside their module in different ways:
>> 1. private/fileprivate/internal enum: cases can be added freely.  All 
>> clients are in the same module, so the enum is implicitly fragile, and all 
>> switches within the current module may therefore be exhaustive.
>> 2. public enum (i.e., one that isn’t marked fragile): cases may be added 
>> freely.   Within the module that defines the enum, switches may be 
>> exhaustive.  However, because the enum is public and non-fragile, clients 
>> outside the current module must be prepared for the enum to add additional 
>> cases in future revisions of the API, and therefore they cannot exhaustively 
>> match the cases of the enum.
> 
> Just small note. As I understand, this is a source breaking suggestion, no?
> I mean any client code for 'public enum' coming from another module, will 
> have to add 'default' case in 'switch'. So, the previously correct code will 
> not compile. Or do you suggest to raise a warning only for the first time and 
> raise an error in next version of Swift?

Yes. By defaulting to “non fragile” we add a source incompatibility, because 
Swift is currently assuming fragility. In Jordan’s proposal, it is assuming 
fragility/exhaustive by default, and therefore would be source compatible. Good 
point.

I keep wavering back and forth on the importance of Source Compatibility with 
this one. Defaulting to “exhaustive” seems dangerous to me. It makes your 
framework (and future versions of it) fragile without ever having to think 
about it. At least if the keyword of “exhaustive” or “fragile” or “sealed” 
meant that you actively chose the fragility that will handcuff you later down 
the road.

> 
>> 3. fragile public enum: cases may not be added, because that would break the 
>> fragility guarantee.  As such, clients within or outside of hte current 
>> module may exhaustively match against the enum.
> 
> I think 'fragile' word does not reflect what is guaranteed for this enum. The 
> author guaranteed that this enum will not be changed, not "this enum can 
> broke your code". Can't we use 'sealed'/'closed'/'fixed' here?
> 
> Vladimir.
> 
>> This approach gives a very natural user model: app developers don’t have to 
>> care about enum resilience until they mark an enum as public, and even then 
>> they only have to care about it when/if they mark an enum as public.  This 
>> also builds on the notion of fragility - something we need for other nominal 
>> types like structs and classes - so it doesn’t introduce new language 
>> complexity.  Also such an approach is entirely source compatible with Swift 
>> 3/4, which require defaults (this isn’t an accident, it follows from the 
>> anticipated design).
>> This approach doesn’t address the problem of what to do with C though, 
>> because C doesn’t have a reasonable notion of “extensible” vs 
>> “nonextensible” enum.  As such, we definitely do need an attribute (or 
>> something) to add to Clang.  I think that your proposal for defaulting to 
>> “extensible” and using __attribute__((enum_extensibility(closed))) override 
>> this is perfectly sensible.
>> -Chris
>> ___
>> 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 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-07 Thread Vladimir.S via swift-evolution

On 07.09.2017 7:33, Chris Lattner via swift-evolution wrote:


On Sep 5, 2017, at 5:19 PM, Jordan Rose via swift-evolution 
> wrote:


I've taken everyone's feedback into consideration and written this up as a 
proposal: 
https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md. 
The next step is working on an implementation, but if people have further 
pre-review comments I'd be happy to hear them.


Hi Jordan,

I apologize in advance that I haven’t followed the back and forth on this thread, so 
I’m sorry if these thoughts are duplicative:


I really would prefer to avoid introducing the notion of exhaustive/nonexhaustive 
enums into Swift, and would much prefer that such a thing be limited to C (which 
can’t express this concept already).


We’ve talked about enums many times across years, and it seems like the appropriate 
model follows the generally understood resilience model.  Specifically, there should 
be three different kinds of enums, and the kind should affect users outside their 
module in different ways:


1. private/fileprivate/internal enum: cases can be added freely.  All clients are in 
the same module, so the enum is implicitly fragile, and all switches within the 
current module may therefore be exhaustive.


2. public enum (i.e., one that isn’t marked fragile): cases may be added freely. 
  Within the module that defines the enum, switches may be exhaustive.  However, 
because the enum is public and non-fragile, clients outside the current module must 
be prepared for the enum to add additional cases in future revisions of the API, and 
therefore they cannot exhaustively match the cases of the enum.


Just small note. As I understand, this is a source breaking suggestion, no?
I mean any client code for 'public enum' coming from another module, will have to add 
'default' case in 'switch'. So, the previously correct code will not compile. Or do 
you suggest to raise a warning only for the first time and raise an error in next 
version of Swift?




3. fragile public enum: cases may not be added, because that would break the 
fragility guarantee.  As such, clients within or outside of hte current module may 
exhaustively match against the enum.




I think 'fragile' word does not reflect what is guaranteed for this enum. The author 
guaranteed that this enum will not be changed, not "this enum can broke your code". 
Can't we use 'sealed'/'closed'/'fixed' here?


Vladimir.



This approach gives a very natural user model: app developers don’t have to care 
about enum resilience until they mark an enum as public, and even then they only have 
to care about it when/if they mark an enum as public.  This also builds on the notion 
of fragility - something we need for other nominal types like structs and classes - 
so it doesn’t introduce new language complexity.  Also such an approach is entirely 
source compatible with Swift 3/4, which require defaults (this isn’t an accident, it 
follows from the anticipated design).


This approach doesn’t address the problem of what to do with C though, because C 
doesn’t have a reasonable notion of “extensible” vs “nonextensible” enum.  As such, 
we definitely do need an attribute (or something) to add to Clang.  I think that your 
proposal for defaulting to “extensible” and 
using __attribute__((enum_extensibility(closed))) override this is perfectly sensible.


-Chris






___
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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Rod Brown via swift-evolution


> On 7 Sep 2017, at 2:33 pm, Chris Lattner via swift-evolution 
>  wrote:
> 
> 
>> On Sep 5, 2017, at 5:19 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> I've taken everyone's feedback into consideration and written this up as a 
>> proposal: 
>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>  
>> .
>>  The next step is working on an implementation, but if people have further 
>> pre-review comments I'd be happy to hear them.
> 
> Hi Jordan,
> 
> I apologize in advance that I haven’t followed the back and forth on this 
> thread, so I’m sorry if these thoughts are duplicative:
> 
> I really would prefer to avoid introducing the notion of 
> exhaustive/nonexhaustive enums into Swift, and would much prefer that such a 
> thing be limited to C (which can’t express this concept already).
> 
> We’ve talked about enums many times across years, and it seems like the 
> appropriate model follows the generally understood resilience model.  
> Specifically, there should be three different kinds of enums, and the kind 
> should affect users outside their module in different ways:
> 
> 1. private/fileprivate/internal enum: cases can be added freely.  All clients 
> are in the same module, so the enum is implicitly fragile, and all switches 
> within the current module may therefore be exhaustive.
> 
> 2. public enum (i.e., one that isn’t marked fragile): cases may be added 
> freely.  Within the module that defines the enum, switches may be exhaustive. 
>  However, because the enum is public and non-fragile, clients outside the 
> current module must be prepared for the enum to add additional cases in 
> future revisions of the API, and therefore they cannot exhaustively match the 
> cases of the enum.
> 
> 3. fragile public enum: cases may not be added, because that would break the 
> fragility guarantee.  As such, clients within or outside of hte current 
> module may exhaustively match against the enum.
> 
> 
> This approach gives a very natural user model: app developers don’t have to 
> care about enum resilience until they mark an enum as public, and even then 
> they only have to care about it when/if they mark an enum as public.  This 
> also builds on the notion of fragility - something we need for other nominal 
> types like structs and classes - so it doesn’t introduce new language 
> complexity.  Also such an approach is entirely source compatible with Swift 
> 3/4, which require defaults (this isn’t an accident, it follows from the 
> anticipated design).
> 
> This approach doesn’t address the problem of what to do with C though, 
> because C doesn’t have a reasonable notion of “extensible” vs “nonextensible” 
> enum.  As such, we definitely do need an attribute (or something) to add to 
> Clang.  I think that your proposal for defaulting to “extensible” and using 
> __attribute__((enum_extensibility(closed))) override this is perfectly 
> sensible.
> 
> -Chris
> 

Hi Chris,

I think I agree with you in general, with 1 exception:

I think the wording “fragile”, while technically correct, implies the exact 
opposite of the promise contract, namely that it will not change between 
releases of your framework. Perhaps a term like “concrete” would be more 
appropriate? It would be fragile in that it is a fragile interface, but it 
would be concrete as a promise to external dependencies. If you are 
exhaustively enumerating, you’re basing it on the notion that it won’t change, 
not that it’s "easy to break” (which fragile as a word would seem to imply).

- Rod


> 
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Chris Lattner via swift-evolution

> On Sep 5, 2017, at 5:19 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> I've taken everyone's feedback into consideration and written this up as a 
> proposal: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>  
> .
>  The next step is working on an implementation, but if people have further 
> pre-review comments I'd be happy to hear them.

Hi Jordan,

I apologize in advance that I haven’t followed the back and forth on this 
thread, so I’m sorry if these thoughts are duplicative:

I really would prefer to avoid introducing the notion of 
exhaustive/nonexhaustive enums into Swift, and would much prefer that such a 
thing be limited to C (which can’t express this concept already).

We’ve talked about enums many times across years, and it seems like the 
appropriate model follows the generally understood resilience model.  
Specifically, there should be three different kinds of enums, and the kind 
should affect users outside their module in different ways:

1. private/fileprivate/internal enum: cases can be added freely.  All clients 
are in the same module, so the enum is implicitly fragile, and all switches 
within the current module may therefore be exhaustive.

2. public enum (i.e., one that isn’t marked fragile): cases may be added 
freely.  Within the module that defines the enum, switches may be exhaustive.  
However, because the enum is public and non-fragile, clients outside the 
current module must be prepared for the enum to add additional cases in future 
revisions of the API, and therefore they cannot exhaustively match the cases of 
the enum.

3. fragile public enum: cases may not be added, because that would break the 
fragility guarantee.  As such, clients within or outside of hte current module 
may exhaustively match against the enum.


This approach gives a very natural user model: app developers don’t have to 
care about enum resilience until they mark an enum as public, and even then 
they only have to care about it when/if they mark an enum as public.  This also 
builds on the notion of fragility - something we need for other nominal types 
like structs and classes - so it doesn’t introduce new language complexity.  
Also such an approach is entirely source compatible with Swift 3/4, which 
require defaults (this isn’t an accident, it follows from the anticipated 
design).

This approach doesn’t address the problem of what to do with C though, because 
C doesn’t have a reasonable notion of “extensible” vs “nonextensible” enum.  As 
such, we definitely do need an attribute (or something) to add to Clang.  I 
think that your proposal for defaulting to “extensible” and using 
__attribute__((enum_extensibility(closed))) override this is perfectly sensible.

-Chris




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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Rod Brown via swift-evolution
Hi Brent,

Thanks for the analysis of the issues here. I think you’re right that there are 
two major types of enums, and that there are a set developers tend to switch on 
that are usually fixed, where additional cases won’t make sense.

I think there are several issues that I see with these different ideas, and 
they stem back to a similar source:

1. They are overly complex solutions to a specific problem: inter-library 
variable enums. We would be destroying some of the awesome simplicity and 
design characteristics of enums in Swift to deal with an outlying problem.

2. Project enums should always be exhaustive. Your design introduces 
‘exhaustive’ and has an end goal of removing ‘@nonexhaustive’ but the fact is 
that keyword should be the default internal of a project. It seems an odd 
trajectory change to make purely for public enums.

It would seem much simpler to have a word that denotes that an enum is not 
considered ‘exhaustive’ in public code, or to force users to annotate their 
intention of exhaustive vs extensible when they make their enum public, and 
have intra-project enums remain exhaustive. This then requires a simple 
addition of a default argument to handle outlier cases you may encounter. Your 
solutions seem to me to require a large to deal with a relatively narrow use 
case, radically changing the enum system.

I agree that we could include something as part of @testable to add an 
additional case to test the edge case. We do have specific language elements 
for testing, why not here?

- Rod


> On 6 Sep 2017, at 10:53 pm, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
>> On Sep 5, 2017, at 5:19 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> I've taken everyone's feedback into consideration and written this up as a 
>> proposal: 
>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>  
>> .
>>  The next step is working on an implementation, but if people have further 
>> pre-review comments I'd be happy to hear them.
> 
> I disagree with the choice of `exhaustive` and `nonexhaustive`. They are too 
> long; the more resilient keyword is longer than the more fragile one (and 
> difficult to read!); and they don't match the clang annotation. We may have 
> to compromise on one or two of these, but the combination of all three ought 
> to be considered disqualifying.
> 
> I think `final`/`nonfinal`, `total`/`partial`, `fixed`/? or `permanent`/? are 
> all better because they're shorter, although they all have problems with 
> their antonyms. `candid`/`coy` or `candid`/`shy` produce the right soft 
> default, but are kind of weirdly figurative.
> 
> But I don't think a change of keywords will fix everything here. 
> Fundamentally, I am not convinced that source compatibility of `switch` 
> statements should be weighed so heavily. Based on your survey of Foundation, 
> you suggest that the vast majority of imported enums should source-break all 
> switches in Swift 5. Why is that acceptable, but making Swift enums 
> source-breaking unacceptable?
> 
> I suspect that, in practice, `public` enums tend to fall into two categories:
> 
>   1. "Data enums" which represent important data that happens to consist 
> of a set of alternatives. Outside users will frequently need to switch over 
> these, but they are not very likely to evolve or have private cases.
> 
>   2. "Mode enums" which tweak the behavior of an API. These are very 
> likely to evolve or have private cases, but outside users are not very likely 
> to need to switch over them.
> 
> An example of a data enum would be, as you mentioned, `NSComparisonResult`. 
> People really *do* need to be able to test against it, but barring some 
> fundamental break in the nature of reality, it will only ever have those 
> three cases. So it's fine to make it exhaustive.
> 
> An example of a mode enum would be `UIViewAnimationCurve`, which tells UIKit 
> how to ease an animation. I chose that example because I actually traced a 
> bug just last week to my mistaken impression that this enum had no private 
> cases. I was mapping values of this type to their corresponding 
> `UIViewAnimationOptions` values; because there were private cases, this was 
> Objective-C code, and I didn't include sufficiently aggressive assertions, I 
> ended up reading garbage data from memory. But while debugging this, it 
> struck me that this was actually *really weird* code. How often do you, as a 
> developer outside UIKit, need to interpret the value of a type like 
> `UIViewAnimationCurve`? If the compiler suddenly changed the exhaustiveness 
> behavior of `UIViewAnimationCurve`, probably less than 1% of apps would even 
> notice—and the affected code would probably have latent 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Jose Cheyo Jimenez via swift-evolution
Here is an alternative view. I've been thinking about this and I feel that 
instead of adding this to an enum why not make RawRepresentable structs a swift 
construct. 

You could declare it like this:

enum struct {
   case a, b, c
}

This would be a struct that acts like an enum but it is open like a 
RawRepresentable but using the enum case sugar. 

> On Sep 5, 2017, at 5:37 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> It's in the "Alternatives Considered" section. :-) That was my desired design 
> when we started, but feedback convinced me that the break from Swift 4 mode 
> would be too drastic. The same valid code would have a different meaning 
> whether you were writing Swift 4 or Swift 5.
> 
> Jordan
> 
> 
>> On Sep 5, 2017, at 17:30, Rod Brown  wrote:
>> 
>> Hi Jordan,
>> 
>> I’m not sure how much bearing on this my comment will have.
>> 
>> Have you considered having only “exhaustive” as a keyword, and make the 
>> default non-exhaustive? It seems that “exhaustive" would be the rarer case, 
>> as it promises a lot more about compatibility (much like there is no such 
>> thing as “non-final”). Also, non exhaustive seems a massive mouthful despite 
>> it probably being the correct term.
>> 
>> - Rod
>> 
>>> On 6 Sep 2017, at 10:19 am, Jordan Rose  wrote:
>>> 
>>> I've taken everyone's feedback into consideration and written this up as a 
>>> proposal: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md.
>>>  The next step is working on an implementation, but if people have further 
>>> pre-review comments I'd be happy to hear them.
>>> 
>>> Jordan
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Brent Royal-Gordon via swift-evolution
> On Sep 5, 2017, at 5:19 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> I've taken everyone's feedback into consideration and written this up as a 
> proposal: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>  
> .
>  The next step is working on an implementation, but if people have further 
> pre-review comments I'd be happy to hear them.

I disagree with the choice of `exhaustive` and `nonexhaustive`. They are too 
long; the more resilient keyword is longer than the more fragile one (and 
difficult to read!); and they don't match the clang annotation. We may have to 
compromise on one or two of these, but the combination of all three ought to be 
considered disqualifying.

I think `final`/`nonfinal`, `total`/`partial`, `fixed`/? or `permanent`/? are 
all better because they're shorter, although they all have problems with their 
antonyms. `candid`/`coy` or `candid`/`shy` produce the right soft default, but 
are kind of weirdly figurative.

But I don't think a change of keywords will fix everything here. Fundamentally, 
I am not convinced that source compatibility of `switch` statements should be 
weighed so heavily. Based on your survey of Foundation, you suggest that the 
vast majority of imported enums should source-break all switches in Swift 5. 
Why is that acceptable, but making Swift enums source-breaking unacceptable?

I suspect that, in practice, `public` enums tend to fall into two categories:

1. "Data enums" which represent important data that happens to consist 
of a set of alternatives. Outside users will frequently need to switch over 
these, but they are not very likely to evolve or have private cases.

2. "Mode enums" which tweak the behavior of an API. These are very 
likely to evolve or have private cases, but outside users are not very likely 
to need to switch over them.

An example of a data enum would be, as you mentioned, `NSComparisonResult`. 
People really *do* need to be able to test against it, but barring some 
fundamental break in the nature of reality, it will only ever have those three 
cases. So it's fine to make it exhaustive.

An example of a mode enum would be `UIViewAnimationCurve`, which tells UIKit 
how to ease an animation. I chose that example because I actually traced a bug 
just last week to my mistaken impression that this enum had no private cases. I 
was mapping values of this type to their corresponding `UIViewAnimationOptions` 
values; because there were private cases, this was Objective-C code, and I 
didn't include sufficiently aggressive assertions, I ended up reading garbage 
data from memory. But while debugging this, it struck me that this was actually 
*really weird* code. How often do you, as a developer outside UIKit, need to 
interpret the value of a type like `UIViewAnimationCurve`? If the compiler 
suddenly changed the exhaustiveness behavior of `UIViewAnimationCurve`, 
probably less than 1% of apps would even notice—and the affected code would 
probably have latent bugs!

Here's my point: Suddenly treating a mode enum as non-exhaustive is 
*technically* source-breaking, but *people aren't doing things to them that 
would break*. It is only the data enums that would actually experience source 
breakage, and we both seem to agree those are relatively uncommon. So I would 
argue the relatively rare source breaks are acceptable.

Basically, what I would suggest is this:

1. In Swift 4.1, we should add a permanent `exhaustive`* keyword and a 
temporary `@nonexhaustive` attribute to Swift. These are no-ops, or maybe 
`@nonexhaustive` simply silences the "unreachable default case" warning.

2. In Swift 4.2 (or whatever Swift 5's Swift 4 mode is called), we 
should warn about any enum which does not have either `exhaustive` or 
`@nonexhaustive` attached to it, but publishes them as non-exhaustive. `switch` 
requires a `default` case for any non-exhaustive public enum.

3. Swift 5 in Swift 5 mode does the same thing, but does *not* warn 
about the absence of `@nonexhaustive`.

4. Swift 5 importing Objective-C treats enums as non-exhaustive by 
default, unless marked with an attribute.

The dummy keywords in Swift 4.1 ensure that developers can write code that 
works in both a true Swift 4 compiler and a Swift 5 compiler in Swift 4 mode. 
(If we don't like that approach, though, we can bump the versions—give Swift 
4.2 the behavior I described for Swift 4, give Swift 5 the behavior I described 
for 4.2, and plan to give Swift 6 the behavior I described for Swift 5.)

* I'm still not super-happy with `exhaustive`, but since `@nonexhaustive` is 
temporary in this scheme, that at least improves one of the complaints about 
it. I think the keywords I discussed above would still be improvements.

  

Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Matthew Johnson via swift-evolution
Hi Jordan,

The proposal looks very reasonable to me.

I don’t have too strong an opinion on this topic, but it occurred to me that 
your discussion of `future` left out one possible design approach.  We could 
restrict code in the `future` clause to be `break` or `fatalError()`.  One of 
these is probably what most people would do any way and neither really requires 
testing.  As you noted, it will be possible to have untestable code in a 
`default` clause which is probably what people asking for `future` will have in 
the relevant switch statements.  

Supporting `future` does seem like a nice way to allow libraries to add cases 
without a breaking change while allowing users to opt-in to a breaking change 
when that happens.  It’s a nice compromise that doesn’t appear to harm anyone.  

The main argument against it is: what are the use cases?  I haven’t thought 
enough about it to answer that question.  I would challenge people asking for 
`future` to try to provide some concrete examples, probably referencing enums 
in Apple frameworks.  Maybe if sufficient motivation can be demonstrated we 
should reconsider the more limited form of `future` that doesn’t involve 
untestable code.  On the other hand, `future` is something that can always be 
added later.

As I said, I don’t have a strong opinion about this either way at the moment.

Matthew

> On Sep 5, 2017, at 7:19 PM, Jordan Rose  wrote:
> 
> I've taken everyone's feedback into consideration and written this up as a 
> proposal: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>  
> .
>  The next step is working on an implementation, but if people have further 
> pre-review comments I'd be happy to hear them.
> 
> Jordan
> 
> 
>> On Aug 8, 2017, at 15:27, Jordan Rose > > wrote:
>> 
>> Hi, everyone. Now that Swift 5 is starting up, I'd like to circle back to an 
>> issue that's been around for a while: the source compatibility of enums. 
>> Today, it's an error to switch over an enum without handling all the cases, 
>> but this breaks down in a number of ways:
>> 
>> - A C enum may have "private cases" that aren't defined inside the original 
>> enum declaration, and there's no way to detect these in a switch without 
>> dropping down to the rawValue.
>> - For the same reason, the compiler-synthesized 'init(rawValue:)' on an 
>> imported enum never produces 'nil', because who knows how anyone's using C 
>> enums anyway?
>> - Adding a new case to a Swift enum in a library breaks any client code that 
>> was trying to switch over it.
>> 
>> (This list might sound familiar, and that's because it's from a message of 
>> mine on a thread started by Matthew Johnson back in February called "[Pitch] 
>> consistent public access modifiers". Most of the rest of this email is going 
>> to go the same way, because we still need to make progress here.)
>> 
>> At the same time, we really like our exhaustive switches, especially over 
>> enums we define ourselves. And there's a performance side to this whole 
>> thing too; if all cases of an enum are known, it can be passed around much 
>> more efficiently than if it might suddenly grow a new case containing a 
>> struct with 5000 Strings in it.
>> 
>> 
>> Behavior
>> 
>> I think there's certain behavior that is probably not terribly controversial:
>> 
>> - When enums are imported from Apple frameworks, they should always require 
>> a default case, except for a few exceptions like NSRectEdge. (It's Apple's 
>> job to handle this and get it right, but if we get it wrong with an imported 
>> enum there's still the workaround of dropping down to the raw value.)
>> - When I define Swift enums in the current framework, there's obviously no 
>> compatibility issues; we should allow exhaustive switches.
>> 
>> Everything else falls somewhere in the middle, both for enums defined in 
>> Objective-C:
>> 
>> - If I define an Objective-C enum in the current framework, should it allow 
>> exhaustive switching, because there are no compatibility issues, or not, 
>> because there could still be private cases defined in a .m file?
>> - If there's an Objective-C enum in another framework (that I built locally 
>> with Xcode, Carthage, CocoaPods, SwiftPM, etc.), should it allow exhaustive 
>> switching, because there are no binary compatibility issues, or not, because 
>> there may be source compatibility issues? We'd really like adding a new enum 
>> case to not be a breaking change even at the source level.
>> - If there's an Objective-C enum coming in through a bridging header, should 
>> it allow exhaustive switching, because I might have defined it myself, or 
>> not, because it might be non-modular content I've used the bridging header 
>> to import?
>> 
>> And in Swift:

Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Rod Brown via swift-evolution

>> I see the logic of this position, but it traps at cases which are unforeseen 
>> unrelated to OS releases. As this proposal notes, there are cases that Apple 
>> uses internal of their frameworks that they consider private may still be 
>> passed through your API.
>> 
>> For example, if there was a new button type, and you enumerated all public 
>> types in your method, but UIKit had a private custom button type, you 
>> couldn’t catch on it, nor would you have any idea that it existed. This 
>> isn’t related to the release cycle timing, but you’re still going to start 
>> crashing despite the fact that you believe you’ve exhaustively handled all 
>> cases.
> 
> Fully understood, though when you are in the middle of some calculation, you 
> are unlikely to do anything by fatalError in the "future" case...
> 
> Imagine e.g. your DateFormatter and you get a new Style in the formatting - 
> what do you do? Fallback on a different one? I personally would simply call 
> fatalError in the future case anyway…

I would tend to agree, which is part of why I think “future” doesn’t make sense 
and should stay in the Alternatives Considered but dropped.

I think the point of extensible/nonexhaustive enums is precisely so we think 
about what are appropriate defaults, otherwise we would just add a “fatalError” 
into the compilation of Switches when no case is caught, and that would be the 
end of this proposal.

In your example, is there a fair default fallback for this behaviour? Just 
choose a reasonable default date style and run with it as an appropriate 
fallback. 95% of the time, there are more reasonable solutions than crashing 
just because your text on screen line breaks weirdly.

Only in occasions where either a) the default case makes no sense, or b) I 
really cannot use a fair default in this calculation, would I fatalError in 
this case. This would seem to me to be far more reasonable than “I can’t hard 
code it, stop the presses, crash everything, blow up the world” for most cases. 
Additionally, it would seem wise for a framework developer to annotate why they 
marked their enum as “nonexhaustive” to give some hint as to a reasonable 
handling of these cases, where it’s not clearly evident.

> 
>> 
>> Also, we need to be thinking bigger than just the Apple Ecosystem. While 
>> Swift started on the Mac and iOS, this is hardly guaranteed, nor are release 
>> timings. Also, just because the dynamic frameworks update at regular 
>> intervals now, doesn’t mean the same will happen on Linux, where a 
>> dynamically linked framework could just update without anyone knowing. Part 
>> of the consideration of ABI stability isn’t just for Apple to ship 
>> frameworks, but for anyone to ship frameworks that are not contained within 
>> the signed bundle of the application. It is short sighted to say “well, this 
>> works for us right now” in my opinion. Part of this discussion is to mature 
>> Swift away from these kinds of assumptions (Apple, Obj-C, etc).

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Charlie Monroe via swift-evolution

> On Sep 6, 2017, at 8:50 AM, Rod Brown  wrote:
> 
> 
>> On 6 Sep 2017, at 2:31 pm, Charlie Monroe > > wrote:
>>> On Sep 6, 2017, at 5:44 AM, Rod Brown via swift-evolution 
>>> > wrote:
>>> I think what you’re really asking for here is the “future” case mentioned 
>>> in the Alternatives Considered section. I think that Jordan makes a good 
>>> point that this would result in untestable code, which is bad practice. 
>>> While the lack of clear highlighting of non-exhaustive cases is 
>>> undesirable, I think untestable code is a much larger problem here.
>> 
>> This is generally the switch! that I've suggested listed in alternatives as 
>> well - that generally brings current behavior. For a project that is 
>> regularly maintained, I believe that this makes sense given that the enums 
>> are only likely to change once a year at most (with new OS releases)…
> 
> I see the logic of this position, but it traps at cases which are unforeseen 
> unrelated to OS releases. As this proposal notes, there are cases that Apple 
> uses internal of their frameworks that they consider private may still be 
> passed through your API.
> 
> For example, if there was a new button type, and you enumerated all public 
> types in your method, but UIKit had a private custom button type, you 
> couldn’t catch on it, nor would you have any idea that it existed. This isn’t 
> related to the release cycle timing, but you’re still going to start crashing 
> despite the fact that you believe you’ve exhaustively handled all cases.

Fully understood, though when you are in the middle of some calculation, you 
are unlikely to do anything by fatalError in the "future" case...

Imagine e.g. your DateFormatter and you get a new Style in the formatting - 
what do you do? Fallback on a different one? I personally would simply call 
fatalError in the future case anyway...

> 
> Also, we need to be thinking bigger than just the Apple Ecosystem. While 
> Swift started on the Mac and iOS, this is hardly guaranteed, nor are release 
> timings. Also, just because the dynamic frameworks update at regular 
> intervals now, doesn’t mean the same will happen on Linux, where a 
> dynamically linked framework could just update without anyone knowing. Part 
> of the consideration of ABI stability isn’t just for Apple to ship 
> frameworks, but for anyone to ship frameworks that are not contained within 
> the signed bundle of the application. It is short sighted to say “well, this 
> works for us right now” in my opinion. Part of this discussion is to mature 
> Swift away from these kinds of assumptions (Apple, Obj-C, etc).
> 
>> 
>>> 
>>> Either way we need a way to handle forward compatibility for our code when 
>>> cases get added to external frameworks, that much is clear. Swift is broken 
>>> in regards to this, and we need to handle it somehow. I’m hoping you’re not 
>>> suggesting that we just don’t make this change at all. We need this for 
>>> forward compatibility for framework development with Swift.
>>> _
>>> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Rod Brown via swift-evolution


> On 6 Sep 2017, at 4:35 pm, David Hart  wrote:
> 
> Hi Jordan,
> 
> I like this new direction. But I have Rod’s inverse question: have you 
> considered only having the nonexhaustive keyword? Similar to how non-final 
> doesn't exist because its opposite is the default behaviour. That would also 
> free us from searching for a good pair of keywords and only find one good 
> keyword (extensible, expandable, …) which doesn’t contain a negative.

I was thinking the same. If exhaustive is the default, and how Swift has always 
worked, then why have that keyword anyway? I like extensible/expandable but I 
worry the connotation some might come away with that you could add cases 
externally, which is not in scope.

> 
> David.
> 
>> On 6 Sep 2017, at 02:36, Jordan Rose > > wrote:
>> 
>> It's in the "Alternatives Considered" section. :-) That was my desired 
>> design when we started, but feedback convinced me that the break from Swift 
>> 4 mode would be too drastic. The same valid code would have a different 
>> meaning whether you were writing Swift 4 or Swift 5.
>> 
>> Jordan
>> 
>> 
>>> On Sep 5, 2017, at 17:30, Rod Brown >> > wrote:
>>> 
>>> Hi Jordan,
>>> 
>>> I’m not sure how much bearing on this my comment will have.
>>> 
>>> Have you considered having only “exhaustive” as a keyword, and make the 
>>> default non-exhaustive? It seems that “exhaustive" would be the rarer case, 
>>> as it promises a lot more about compatibility (much like there is no such 
>>> thing as “non-final”). Also, non exhaustive seems a massive mouthful 
>>> despite it probably being the correct term.
>>> 
>>> - Rod
>>> 
 On 6 Sep 2017, at 10:19 am, Jordan Rose > wrote:
 
 I've taken everyone's feedback into consideration and written this up as a 
 proposal: 
 https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
  
 .
  The next step is working on an implementation, but if people have further 
 pre-review comments I'd be happy to hear them.
 
 Jordan
>> 
> 

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Rod Brown via swift-evolution

> On 6 Sep 2017, at 2:31 pm, Charlie Monroe  wrote:
>> On Sep 6, 2017, at 5:44 AM, Rod Brown via swift-evolution 
>> > wrote:
>> I think what you’re really asking for here is the “future” case mentioned in 
>> the Alternatives Considered section. I think that Jordan makes a good point 
>> that this would result in untestable code, which is bad practice. While the 
>> lack of clear highlighting of non-exhaustive cases is undesirable, I think 
>> untestable code is a much larger problem here.
> 
> This is generally the switch! that I've suggested listed in alternatives as 
> well - that generally brings current behavior. For a project that is 
> regularly maintained, I believe that this makes sense given that the enums 
> are only likely to change once a year at most (with new OS releases)…

I see the logic of this position, but it traps at cases which are unforeseen 
unrelated to OS releases. As this proposal notes, there are cases that Apple 
uses internal of their frameworks that they consider private may still be 
passed through your API.

For example, if there was a new button type, and you enumerated all public 
types in your method, but UIKit had a private custom button type, you couldn’t 
catch on it, nor would you have any idea that it existed. This isn’t related to 
the release cycle timing, but you’re still going to start crashing despite the 
fact that you believe you’ve exhaustively handled all cases.

Also, we need to be thinking bigger than just the Apple Ecosystem. While Swift 
started on the Mac and iOS, this is hardly guaranteed, nor are release timings. 
Also, just because the dynamic frameworks update at regular intervals now, 
doesn’t mean the same will happen on Linux, where a dynamically linked 
framework could just update without anyone knowing. Part of the consideration 
of ABI stability isn’t just for Apple to ship frameworks, but for anyone to 
ship frameworks that are not contained within the signed bundle of the 
application. It is short sighted to say “well, this works for us right now” in 
my opinion. Part of this discussion is to mature Swift away from these kinds of 
assumptions (Apple, Obj-C, etc).

> 
>> 
>> Either way we need a way to handle forward compatibility for our code when 
>> cases get added to external frameworks, that much is clear. Swift is broken 
>> in regards to this, and we need to handle it somehow. I’m hoping you’re not 
>> suggesting that we just don’t make this change at all. We need this for 
>> forward compatibility for framework development with Swift.
>> _
>> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread David Hart via swift-evolution
Hi Jordan,

I like this new direction. But I have Rod’s inverse question: have you 
considered only having the nonexhaustive keyword? Similar to how non-final 
doesn't exist because its opposite is the default behaviour. That would also 
free us from searching for a good pair of keywords and only find one good 
keyword (extensible, expandable, …) which doesn’t contain a negative.

David.

> On 6 Sep 2017, at 02:36, Jordan Rose  wrote:
> 
> It's in the "Alternatives Considered" section. :-) That was my desired design 
> when we started, but feedback convinced me that the break from Swift 4 mode 
> would be too drastic. The same valid code would have a different meaning 
> whether you were writing Swift 4 or Swift 5.
> 
> Jordan
> 
> 
>> On Sep 5, 2017, at 17:30, Rod Brown > > wrote:
>> 
>> Hi Jordan,
>> 
>> I’m not sure how much bearing on this my comment will have.
>> 
>> Have you considered having only “exhaustive” as a keyword, and make the 
>> default non-exhaustive? It seems that “exhaustive" would be the rarer case, 
>> as it promises a lot more about compatibility (much like there is no such 
>> thing as “non-final”). Also, non exhaustive seems a massive mouthful despite 
>> it probably being the correct term.
>> 
>> - Rod
>> 
>>> On 6 Sep 2017, at 10:19 am, Jordan Rose >> > wrote:
>>> 
>>> I've taken everyone's feedback into consideration and written this up as a 
>>> proposal: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>>  
>>> .
>>>  The next step is working on an implementation, but if people have further 
>>> pre-review comments I'd be happy to hear them.
>>> 
>>> Jordan
> 

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-05 Thread Charlie Monroe via swift-evolution

> On Sep 6, 2017, at 5:44 AM, Rod Brown via swift-evolution 
>  wrote:
> 
>> 
>> On 6 Sep 2017, at 12:05 pm, Jarod Long via swift-evolution 
>> > wrote:
>> 
>> From the perspective of primarily an app developer rather than library 
>> author, I'm not a big fan of this change. I find myself in the "unhappy with 
>> the loss of compiler warnings" camp -- if I'm switching over every case of 
>> an enum, then I almost certainly want to be notified that a new case has 
>> been added by way of a compiler error than via the arbitrary runtime 
>> behavior I added in the previously-unreachable default case.
> 
> I think what you’re really asking for here is the “future” case mentioned in 
> the Alternatives Considered section. I think that Jordan makes a good point 
> that this would result in untestable code, which is bad practice. While the 
> lack of clear highlighting of non-exhaustive cases is undesirable, I think 
> untestable code is a much larger problem here.

This is generally the switch! that I've suggested listed in alternatives as 
well - that generally brings current behavior. For a project that is regularly 
maintained, I believe that this makes sense given that the enums are only 
likely to change once a year at most (with new OS releases)...

> 
> Either way we need a way to handle forward compatibility for our code when 
> cases get added to external frameworks, that much is clear. Swift is broken 
> in regards to this, and we need to handle it somehow. I’m hoping you’re not 
> suggesting that we just don’t make this change at all. We need this for 
> forward compatibility for framework development with Swift.
> 
>> 
>> This seems like a clear situation where source compatibility is not desired 
>> to me. For those who want to maximize compatibility, it is possible to opt 
>> into it by adding a default case to an exhaustive switch over a library 
>> enum, but the reverse is not true if this change is made as-is. You can't 
>> opt into an exhaustive switch for nonexhaustive enums if handling every case 
>> is valued over source compatibility.
>> 
>> A secondary concern I have is that this introduces extra complexity that 
>> could be confusing for new Swift developers. The current enum exhaustivity 
>> rules are consistent and easy to explain, but they become more cumbersome 
>> with this added exception that only applies to some enums that specifically 
>> only come from outside the current module. If this change is made, I would 
>> encourage some effort towards a specific error message when switching over 
>> all cases of a nonexhaustive enum without a default case. Rather than the 
>> existing "Switch must be exhaustive", I think it would go a long way towards 
>> avoiding confusion to say something like "Switch over a nonexhaustive enum 
>> must have a default case".
>> 
>> In any case, I don't think these are terrible issues -- I agree with the 
>> proposal's statement that switches over nonexhaustive enums are generally 
>> uncommon. But if that's true, it feels like the source compatibility 
>> motivation is weak, since not much code is affected anyways. Perhaps the 
>> benefits from a library author's perspective make this change worth it, but 
>> at least for me and my coworkers, it would be an unwelcome change overall.
>> 
>> Jarod
>> 
>> On Sep 5, 2017, 17:19 -0700, Jordan Rose via swift-evolution 
>> >, wrote:
>>> I've taken everyone's feedback into consideration and written this up as a 
>>> proposal: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>>  
>>> .
>>>  The next step is working on an implementation, but if people have further 
>>> pre-review comments I'd be happy to hear them.
>>> 
>>> Jordan
>>> 
>>> 
 On Aug 8, 2017, at 15:27, Jordan Rose > wrote:
 
 Hi, everyone. Now that Swift 5 is starting up, I'd like to circle back to 
 an issue that's been around for a while: the source compatibility of 
 enums. Today, it's an error to switch over an enum without handling all 
 the cases, but this breaks down in a number of ways:
 
 - A C enum may have "private cases" that aren't defined inside the 
 original enum declaration, and there's no way to detect these in a switch 
 without dropping down to the rawValue.
 - For the same reason, the compiler-synthesized 'init(rawValue:)' on an 
 imported enum never produces 'nil', because who knows how anyone's using C 
 enums anyway?
 - Adding a new case to a Swift enum in a library breaks any client code 
 that was trying to switch over it.
 
 (This list might sound familiar, and that's 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-05 Thread Jarod Long via swift-evolution
>From the perspective of primarily an app developer rather than library author, 
>I'm not a big fan of this change. I find myself in the "unhappy with the loss 
>of compiler warnings" camp -- if I'm switching over every case of an enum, 
>then I almost certainly want to be notified that a new case has been added by 
>way of a compiler error than via the arbitrary runtime behavior I added in the 
>previously-unreachable default case.

This seems like a clear situation where source compatibility is not desired to 
me. For those who want to maximize compatibility, it is possible to opt into it 
by adding a default case to an exhaustive switch over a library enum, but the 
reverse is not true if this change is made as-is. You can't opt into an 
exhaustive switch for nonexhaustive enums if handling every case is valued over 
source compatibility.

A secondary concern I have is that this introduces extra complexity that could 
be confusing for new Swift developers. The current enum exhaustivity rules are 
consistent and easy to explain, but they become more cumbersome with this added 
exception that only applies to some enums that specifically only come from 
outside the current module. If this change is made, I would encourage some 
effort towards a specific error message when switching over all cases of a 
nonexhaustive enum without a default case. Rather than the existing "Switch 
must be exhaustive", I think it would go a long way towards avoiding confusion 
to say something like "Switch over a nonexhaustive enum must have a default 
case".

In any case, I don't think these are terrible issues -- I agree with the 
proposal's statement that switches over nonexhaustive enums are generally 
uncommon. But if that's true, it feels like the source compatibility motivation 
is weak, since not much code is affected anyways. Perhaps the benefits from a 
library author's perspective make this change worth it, but at least for me and 
my coworkers, it would be an unwelcome change overall.

Jarod

On Sep 5, 2017, 17:19 -0700, Jordan Rose via swift-evolution 
, wrote:
> I've taken everyone's feedback into consideration and written this up as a 
> proposal: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md.
>  The next step is working on an implementation, but if people have further 
> pre-review comments I'd be happy to hear them.
>
> Jordan
>
>
> > On Aug 8, 2017, at 15:27, Jordan Rose  wrote:
> >
> > Hi, everyone. Now that Swift 5 is starting up, I'd like to circle back to 
> > an issue that's been around for a while: the source compatibility of enums. 
> > Today, it's an error to switch over an enum without handling all the cases, 
> > but this breaks down in a number of ways:
> >
> > - A C enum may have "private cases" that aren't defined inside the original 
> > enum declaration, and there's no way to detect these in a switch without 
> > dropping down to the rawValue.
> > - For the same reason, the compiler-synthesized 'init(rawValue:)' on an 
> > imported enum never produces 'nil', because who knows how anyone's using C 
> > enums anyway?
> > - Adding a new case to a Swift enum in a library breaks any client code 
> > that was trying to switch over it.
> >
> > (This list might sound familiar, and that's because it's from a message of 
> > mine on a thread started by Matthew Johnson back in February called 
> > "[Pitch] consistent public access modifiers". Most of the rest of this 
> > email is going to go the same way, because we still need to make progress 
> > here.)
> >
> > At the same time, we really like our exhaustive switches, especially over 
> > enums we define ourselves. And there's a performance side to this whole 
> > thing too; if all cases of an enum are known, it can be passed around much 
> > more efficiently than if it might suddenly grow a new case containing a 
> > struct with 5000 Strings in it.
> >
> >
> > Behavior
> >
> > I think there's certain behavior that is probably not terribly 
> > controversial:
> >
> > - When enums are imported from Apple frameworks, they should always require 
> > a default case, except for a few exceptions like NSRectEdge. (It's Apple's 
> > job to handle this and get it right, but if we get it wrong with an 
> > imported enum there's still the workaround of dropping down to the raw 
> > value.)
> > - When I define Swift enums in the current framework, there's obviously no 
> > compatibility issues; we should allow exhaustive switches.
> >
> > Everything else falls somewhere in the middle, both for enums defined in 
> > Objective-C:
> >
> > - If I define an Objective-C enum in the current framework, should it allow 
> > exhaustive switching, because there are no compatibility issues, or not, 
> > because there could still be private cases defined in a .m file?
> > - If there's an Objective-C enum in another framework (that I built locally 
> > with 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-05 Thread Rod Brown via swift-evolution
Hi Jordan,

Upon further reflection, I’m going to withdraw my concerns about the defaulting 
and I think it’s the right solution after all. This is due to several thoughts 
I had rolling it around my head:

1. In a private project, you would expect all cases to be exhaustive, as this 
is guaranteed by the compiler (no compatibility concerns). Exhaustive makes 
sense here, as it has always done in Swift code, and is why it was the 
behaviour since Swift 1.
2. When we make projects public, we already need to vet them for compatibility 
concerns with final etc. This should be part of the process of making them 
public.
3. It's source compatible with libraries, as mentioned in the proposal.

I can imagine there will still be a tonne of work needed for apps compiling 
against Apple’s Obj-C SDKs when Swift 5 comes out due to this change. Almost 
all enums will become nonexhaustive, but this will then show up in 
documentation changes, header updates etc, and as you’ve mentioned, it will 
avoid confusion.

Sorry! I think I just needed some time to roll it around my head a bit haha

- Rod



> On 6 Sep 2017, at 10:47 am, Rod Brown via swift-evolution 
>  wrote:
> 
> Ah yes, my eye skipped that alternative for some reason! Sorry.
> 
> I’d be concerned that avoiding a default is a fix for a compatibility 
> problem, not a language design decision. If we look back in 5 years and say 
> “why do we need to keep writing nonexhaustive everywhere?”, we’ll have to say 
> “there were compatibility problems with Swift 4-to-5”. That reeks of a 
> language I just want to walk away from. Yuk.
> 
> In this case, either way, we’ll need to do some work. So why not let the 
> migrator migrate this code correctly to “exhaustive”, which is the current 
> behaviour? I think a decision where either way we break source compatibility 
> should be done in the interest of language design, not in the short term 
> interest of avoiding confusion.
> 
> But that’s just my 2c.
> 
> Thanks,
> 
> Rod
> 
>  
> 
>> On 6 Sep 2017, at 10:36 am, Jordan Rose > > wrote:
>> 
>> It's in the "Alternatives Considered" section. :-) That was my desired 
>> design when we started, but feedback convinced me that the break from Swift 
>> 4 mode would be too drastic. The same valid code would have a different 
>> meaning whether you were writing Swift 4 or Swift 5.
>> 
>> Jordan
>> 
>> 
>>> On Sep 5, 2017, at 17:30, Rod Brown >> > wrote:
>>> 
>>> Hi Jordan,
>>> 
>>> I’m not sure how much bearing on this my comment will have.
>>> 
>>> Have you considered having only “exhaustive” as a keyword, and make the 
>>> default non-exhaustive? It seems that “exhaustive" would be the rarer case, 
>>> as it promises a lot more about compatibility (much like there is no such 
>>> thing as “non-final”). Also, non exhaustive seems a massive mouthful 
>>> despite it probably being the correct term.
>>> 
>>> - Rod
>>> 
 On 6 Sep 2017, at 10:19 am, Jordan Rose > wrote:
 
 I've taken everyone's feedback into consideration and written this up as a 
 proposal: 
 https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
  
 .
  The next step is working on an implementation, but if people have further 
 pre-review comments I'd be happy to hear them.
 
 Jordan
>> 
> 
> ___
> 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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-05 Thread Rod Brown via swift-evolution
Ah yes, my eye skipped that alternative for some reason! Sorry.

I’d be concerned that avoiding a default is a fix for a compatibility problem, 
not a language design decision. If we look back in 5 years and say “why do we 
need to keep writing nonexhaustive everywhere?”, we’ll have to say “there were 
compatibility problems with Swift 4-to-5”. That reeks of a language I just want 
to walk away from. Yuk.

In this case, either way, we’ll need to do some work. So why not let the 
migrator migrate this code correctly to “exhaustive”, which is the current 
behaviour? I think a decision where either way we break source compatibility 
should be done in the interest of language design, not in the short term 
interest of avoiding confusion.

But that’s just my 2c.

Thanks,

Rod

 

> On 6 Sep 2017, at 10:36 am, Jordan Rose  wrote:
> 
> It's in the "Alternatives Considered" section. :-) That was my desired design 
> when we started, but feedback convinced me that the break from Swift 4 mode 
> would be too drastic. The same valid code would have a different meaning 
> whether you were writing Swift 4 or Swift 5.
> 
> Jordan
> 
> 
>> On Sep 5, 2017, at 17:30, Rod Brown > > wrote:
>> 
>> Hi Jordan,
>> 
>> I’m not sure how much bearing on this my comment will have.
>> 
>> Have you considered having only “exhaustive” as a keyword, and make the 
>> default non-exhaustive? It seems that “exhaustive" would be the rarer case, 
>> as it promises a lot more about compatibility (much like there is no such 
>> thing as “non-final”). Also, non exhaustive seems a massive mouthful despite 
>> it probably being the correct term.
>> 
>> - Rod
>> 
>>> On 6 Sep 2017, at 10:19 am, Jordan Rose >> > wrote:
>>> 
>>> I've taken everyone's feedback into consideration and written this up as a 
>>> proposal: 
>>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>>  
>>> .
>>>  The next step is working on an implementation, but if people have further 
>>> pre-review comments I'd be happy to hear them.
>>> 
>>> Jordan
> 

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-05 Thread Jordan Rose via swift-evolution
It's in the "Alternatives Considered" section. :-) That was my desired design 
when we started, but feedback convinced me that the break from Swift 4 mode 
would be too drastic. The same valid code would have a different meaning 
whether you were writing Swift 4 or Swift 5.

Jordan


> On Sep 5, 2017, at 17:30, Rod Brown  wrote:
> 
> Hi Jordan,
> 
> I’m not sure how much bearing on this my comment will have.
> 
> Have you considered having only “exhaustive” as a keyword, and make the 
> default non-exhaustive? It seems that “exhaustive" would be the rarer case, 
> as it promises a lot more about compatibility (much like there is no such 
> thing as “non-final”). Also, non exhaustive seems a massive mouthful despite 
> it probably being the correct term.
> 
> - Rod
> 
>> On 6 Sep 2017, at 10:19 am, Jordan Rose > > wrote:
>> 
>> I've taken everyone's feedback into consideration and written this up as a 
>> proposal: 
>> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>>  
>> .
>>  The next step is working on an implementation, but if people have further 
>> pre-review comments I'd be happy to hear them.
>> 
>> Jordan

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


Re: [swift-evolution] Enums and Source Compatibility

2017-09-05 Thread Jordan Rose via swift-evolution
I've taken everyone's feedback into consideration and written this up as a 
proposal: 
https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
 
.
 The next step is working on an implementation, but if people have further 
pre-review comments I'd be happy to hear them.

Jordan


> On Aug 8, 2017, at 15:27, Jordan Rose  wrote:
> 
> Hi, everyone. Now that Swift 5 is starting up, I'd like to circle back to an 
> issue that's been around for a while: the source compatibility of enums. 
> Today, it's an error to switch over an enum without handling all the cases, 
> but this breaks down in a number of ways:
> 
> - A C enum may have "private cases" that aren't defined inside the original 
> enum declaration, and there's no way to detect these in a switch without 
> dropping down to the rawValue.
> - For the same reason, the compiler-synthesized 'init(rawValue:)' on an 
> imported enum never produces 'nil', because who knows how anyone's using C 
> enums anyway?
> - Adding a new case to a Swift enum in a library breaks any client code that 
> was trying to switch over it.
> 
> (This list might sound familiar, and that's because it's from a message of 
> mine on a thread started by Matthew Johnson back in February called "[Pitch] 
> consistent public access modifiers". Most of the rest of this email is going 
> to go the same way, because we still need to make progress here.)
> 
> At the same time, we really like our exhaustive switches, especially over 
> enums we define ourselves. And there's a performance side to this whole thing 
> too; if all cases of an enum are known, it can be passed around much more 
> efficiently than if it might suddenly grow a new case containing a struct 
> with 5000 Strings in it.
> 
> 
> Behavior
> 
> I think there's certain behavior that is probably not terribly controversial:
> 
> - When enums are imported from Apple frameworks, they should always require a 
> default case, except for a few exceptions like NSRectEdge. (It's Apple's job 
> to handle this and get it right, but if we get it wrong with an imported enum 
> there's still the workaround of dropping down to the raw value.)
> - When I define Swift enums in the current framework, there's obviously no 
> compatibility issues; we should allow exhaustive switches.
> 
> Everything else falls somewhere in the middle, both for enums defined in 
> Objective-C:
> 
> - If I define an Objective-C enum in the current framework, should it allow 
> exhaustive switching, because there are no compatibility issues, or not, 
> because there could still be private cases defined in a .m file?
> - If there's an Objective-C enum in another framework (that I built locally 
> with Xcode, Carthage, CocoaPods, SwiftPM, etc.), should it allow exhaustive 
> switching, because there are no binary compatibility issues, or not, because 
> there may be source compatibility issues? We'd really like adding a new enum 
> case to not be a breaking change even at the source level.
> - If there's an Objective-C enum coming in through a bridging header, should 
> it allow exhaustive switching, because I might have defined it myself, or 
> not, because it might be non-modular content I've used the bridging header to 
> import?
> 
> And in Swift:
> 
> - If there's a Swift enum in another framework I built locally, should it 
> allow exhaustive switching, because there are no binary compatibility issues, 
> or not, because there may be source compatibility issues? Again, we'd really 
> like adding a new enum case to not be a breaking change even at the source 
> level.
> 
> Let's now flip this to the other side of the equation. I've been talking 
> about us disallowing exhaustive switching, i.e. "if the enum might grow new 
> cases you must have a 'default' in a switch". In previous (in-person) 
> discussions about this feature, it's been pointed out that the code in an 
> otherwise-fully-covered switch is, by definition, unreachable, and therefore 
> untestable. This also isn't a desirable situation to be in, but it's 
> mitigated somewhat by the fact that there probably aren't many framework 
> enums you should exhaustively switch over anyway. (Think about Apple's 
> frameworks again.) I don't have a great answer, though.
> 
> For people who like exhaustive switches, we thought about adding a new kind 
> of 'default'—let's call it 'unknownCase' just to be able to talk about it. 
> This lets you get warnings when you update to a new SDK, but is even more 
> likely to be untested code. We didn't think this was worth the complexity.
> 
> 
> Terminology
> 
> The "Library Evolution 
> " doc (mostly written 
> by me) originally called these "open" and "closed" enums ("requires a 
> default" and "allows exhaustive switching", 

Re: [swift-evolution] Enums and Source Compatibility

2017-08-15 Thread Vladimir.S via swift-evolution

On 12.08.2017 1:37, Jordan Rose wrote:



On Aug 11, 2017, at 02:59, Vladimir.S > 
wrote:


On 11.08.2017 2:37, Jordan Rose wrote:
Both you and Vladimir are bringing up this point, with Vladimir explicitly 
suggesting a "future" case that's different from "default". Again, the pushback we 
get here is that the "future" case is untestable…but maybe that's still an option 
worth having.


I wonder, how the 'default' in exhaustive switch on open enum is testable?

I mean, let's say we have such enum in one of the frameworks:

open enum MyOpenEnum {
 case one
 case two
}

, then in our code:

switch myOpenEnumInstance {
 case .one : ...
 case .two : ...
 default : ... // how this can be tested?
}

I just strongly feel that be able to keep switch exhaustive at the moment of 
compilation - is critical requirement in some cases, when it is very important to 
not forget to process some cases. With just 'default' in switch for open enum - we 
are loosing this compiler's help. This is why 'future' case is required for open enums.


Also, if I understand correctly, we are going to have most of all extern(imported) 
enums as 'open'. So, we are loosing the feature to receive a help for exhaustive 
switch from compiler for most of such enums.


That's true, but I don't know what to do about it. My hypothesis, again, is that this 
won't be common in practice; so far Charlie's been the only one to provide a 
real-world example of when this is useful.




So, do you want to say that we usually will not have open enums which we want to 
switch exhaustive? Probably I can't understand exactly this point.
Seems like you are saying about enums in Foundation/SDK, while I'm thinking about any 
given framework/module, including compiled from 100% Swift code, even made by 
me/colleague.


It will be very interesting to check the number of exhaustive switches in open source 
Swift projects regarding enums imported from other frameworks. So, this can tell us 
if developers often/rarely decided to check each case in external enum, declared in 
some framework. Probably someone have such information?


My request for 'future' block in switch for open enum based on belief that it can be 
also my(as framework's user) decision if *I* want to keep the switch exhaustive in my 
code in some situation. Framework's author just can't foresee all the possible 
situations and requirements of my code. For some reason I still can't accept that 
this should be just decision of framework's author.
I do expect that the lack of 'future' block for open enums decrease the quality of 
Swift code in framework user's code as keep the switch exhaustive will be hard thing 
without compiler's help.
"Cases could be added in this open enum in future" and "I, as a framework author, 
prevents you from having comiller's help to keep switch exhaustive on this enum" 
should not be the same things.



Thinking further, given source compatibility requirement, can we require a change in 
consumer's code (in exhaustive switches) by changing what 'public enum {..}' means?


I mean, currently public enum is treated as 'closed', so you have to be exhaustive or 
have 'default' block. If we make 'usual' declaration of public enum means 'open' - 
we'll break some consumer's code - as starting from this point they have to contain 
'default'/'future' block in exhaustive switch for the same enum declaration.
So, probably, because of this, current 'usual' declaration of public enum should 
means 'closed' enum, just like now. So, all *current* code will just compile. And 
this will provide a space for optimizations for public enums declared with current 
syntax.


Then, in this case, for open enums we need a special marker.
FWIW Right now I see only 3 good candidates:
1. 'open enum'
2. 'public(future) enum'
3. 'public enum MyEnum {case..; case..; future}'
All have pros and cons, while (2) is more explicit and less confusing for me.

But then I was thinking about the Error enums. Most likely it will contain more cases 
in future releases, but by mistake framework's developer exported it without 'open' 
marker, so any new cases will lead to crash in consumer's code.


What if we consider such solution:
* by default 'public enum' means 'closed' enum and we fully support the source 
compatibility requirement
* Swift generates a warning for such enum, something like "Published enum will be 
'closed', but you should consider if you really want this as new cases will crash 
consumer's code. Please use ... to explicitly express your intention"
* developer then can think and decide what is a 'kind' of this enum and use some 
explicit marker to silence the warning and to express intention. For example:
  * 'public(closed)'(or 'public(final)' or 'public(sealed)') for 'closed' enums, and 
'public(future)' for 'open' enums

  OR
  * public enum MyError: Error { case..; case..; final} (for closed) and
public enum MyError: Error { case..; case..; 

Re: [swift-evolution] Enums and Source Compatibility - defaults

2017-08-13 Thread Tino Heth via swift-evolution
> Say we split up Foundation's enums roughly into categories. You have your 
> policies (NSURLCacheStoragePolicy, NSDateFormatterStyle), states/answers 
> (NSURLSessionTaskState, NSQualityOfService), and, well, lists 
> (NSSearchPathDirectory, NSStringEncoding). Given those, I’d say protocols, 
> generics, and zero-cost abstractions are frequently a better choice (but not 
> always). For instance, IMHO a closed protocol better models commonly-used 
> styles.
I agree a lot that enums are not nearly as useful as they seem at first sight, 
and I know I'm not the only one who started with an enum-based solution and 
realised later that it doesn't work out as expected.
But I didn't encounter that with enums in Foundation — obviously, because I'm 
not writing Foundation code ;-), so could you give some concrete examples where 
the different alternatives would be a better fit?
My experience is that enums loose their appeal quickly when you want to attach 
behaviour or properties to the different cases… but I think closed protocols 
would also be just a workaround, inferior compared with case classes and ad-hoc 
union types. 

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


Re: [swift-evolution] Enums and Source Compatibility - defaults

2017-08-12 Thread Rod Brown via swift-evolution
Yes, I see your point, and that’s something I didn’t consider. If we allowed 
extending enums, this would then clearly indicate that “final” means something 
in the present as well - you cannot add cases.

This opens up the can of worms of extending enums, but I think it’s a fair 
point if we ever want to consider it that then “final" really would make the 
most sense.


> On 12 Aug 2017, at 8:28 am, Jordan Rose  wrote:
> 
> "final"'s on my list of possible names! But it's not quite the same as 
> 'final' for classes: "closed" only talks about what might change in the 
> future, while 'final'-on-a-class also states something about the class in the 
> present: it has no subclasses now as well as not gaining any new ones in the 
> future. Still, it could be closed enough that it ends up being the best bet.
> 
> Jordan
> 
> 
>> On Aug 10, 2017, at 22:23, Rod Brown > > wrote:
>> 
>> Hi all,
>> 
>> I thought I’d chime in with my own 2c…
>> 
>> I’d probably prefer something more like “final” and vs non-final. It’s the 
>> concept we’re dancing around - can you add something to extend it?
>> 
>> In which case, final would allow exhaustive use, and non-final would require 
>> handling the default case. Currently all Swift API would convert as “final”, 
>> and all imported Obj-C API (with perhaps exceptions) would import as is and 
>> require a default handling case. This negates the open vs public issue. But 
>> it does also mean that it would become a manual issue inside the module to 
>> mark the API as final to allow exhaustive switches, unless we say 
>> “exhaustive switches allowed on internal/fileprivate/private types”.
>> 
>> Unsure how this plays into the web of things, though…
>> 
>> Thanks,
>> 
>> Rod
>> 
>> 
>> 
>>> On 11 Aug 2017, at 9:41 am, Jordan Rose via swift-evolution 
>>> > wrote:
>>> 
>>> 
>>> 
 On Aug 10, 2017, at 13:00, David Hart > wrote:
 
 
 
 On 10 Aug 2017, at 19:19, Jordan Rose > wrote:
 
> 
> 
>> On Aug 9, 2017, at 22:46, David Hart > > wrote:
>> 
>> 
>>> On 10 Aug 2017, at 02:42, Jordan Rose >> > wrote:
>>> 
>>> :-) As you've all noted, there are some conflicting concerns for the 
>>> default:
>>> 
>>> - Source compatibility: the existing behavior for an unannotated enum 
>>> is "closed".
>>> - Intuition: if you show someone an enum without an explicit 
>>> annotation, they'll probably expect they can switch over it. (I'm going 
>>> to say this is why Zach calls it a "sensible default".)
>>> - Consistency: switches on an enum in the same module can always be 
>>> exhaustive, so having it be different across modules is a bit annoying. 
>>> (But 'public' already acts like this.)
>>> 
>>> vs.
>>> 
>>> - Library evolution: the default should promise less, so that you have 
>>> the opportunity to change it.
>>> - Flexibility: you can emulate an exhaustive switch with a 
>>> non-exhaustive switch using fatalError, but not the other way around.
>>> 
>>> All of this is why I suggested it be an explicit annotation in either 
>>> direction, but Matthew brought up the "keyword soup" problem—if you 
>>> have to write (say) "public finite enum" and "public infinite enum", 
>>> but would never write "private finite enum" or "private infinite enum", 
>>> something is redundant here. Still, I'm uncomfortable with the default 
>>> case being the one that constrains library authors, so at least for 
>>> binary frameworks (those compiled "with resilience") I would want that 
>>> to be explicit. That brings us to one more concern: how different 
>>> should binary frameworks be from source frameworks?
>> 
>> In terms of intuition and consistency, I think we should really try to 
>> learn from the simplicity of public/open:
>> 
>> * When internal, classes are sub-classable by default for convenience, 
>> but can be closed with the final keyword
>> * When public, classes are closed to sub-classing for safety, but can be 
>> opened up with the open keyword (which implies public).
>> 
>> If we try to mirror this behaviour (the keywords are just suggestions, 
>> not important):
>> 
>> * When internal, enums are exhaustive by default for convenience, but 
>> can be opened-up with the partial keyword
>> * When public, enums are non-exhaustive by default for safety, but can 
>> be made exhaustive with the exhaustive keyword (which implies public).
> 
> This is not a correct understanding of the internal/public distinction 

Re: [swift-evolution] Enums and Source Compatibility

2017-08-11 Thread Jordan Rose via swift-evolution


> On Aug 11, 2017, at 02:59, Vladimir.S  wrote:
> 
> On 11.08.2017 2:37, Jordan Rose wrote:
>> Both you and Vladimir are bringing up this point, with Vladimir explicitly 
>> suggesting a "future" case that's different from "default". Again, the 
>> pushback we get here is that the "future" case is untestable…but maybe 
>> that's still an option worth having. 
> 
> I wonder, how the 'default' in exhaustive switch on open enum is testable?
> 
> I mean, let's say we have such enum in one of the frameworks:
> 
> open enum MyOpenEnum {
>  case one
>  case two
> }
> 
> , then in our code:
> 
> switch myOpenEnumInstance {
>  case .one : ...
>  case .two : ...
>  default : ... // how this can be tested?
> }
> 
> I just strongly feel that be able to keep switch exhaustive at the moment of 
> compilation - is critical requirement in some cases, when it is very 
> important to not forget to process some cases. With just 'default' in switch 
> for open enum - we are loosing this compiler's help. This is why 'future' 
> case is required for open enums.
> 
> Also, if I understand correctly, we are going to have most of all 
> extern(imported) enums as 'open'. So, we are loosing the feature to receive a 
> help for exhaustive switch from compiler for most of such enums.

That's true, but I don't know what to do about it. My hypothesis, again, is 
that this won't be common in practice; so far Charlie's been the only one to 
provide a real-world example of when this is useful.


> Moreover, shouldn't we just say that enums, that we have no Swift sources for 
> at the moment of compilation - should *always* be treated as 'open'? If we 
> compile our 'switch' together with the source of switched enum - such enum 
> can not be changed in the future.
> But, if enum is coming from other framework - we have no any control over it, 
> and even author of framework IMO can't be sure in most cases that enum will 
> not be extended in future, and probably we even should not ask author of 
> framework to consider its enum closed, as most likely one can't foresee for 
> sure.
> 
> Wouldn't this be a simpler and more robust model to think about enums in 
> Swift?
> So you know, that *any* enum coming from framework(not from source) - can be 
> changed in future, and so you have to process this case explicitly. In this 
> case we don't need to mark enum as 'open' or 'closed' at all, but for some 
> rare cases, when author of framework *really sure* enum can not be changed in 
> future(and future change in enum will break all the code depending on it), we 
> can introduce some 'final' marker(or @exhaustive directive) to help 
> compiler's optimizations.

Again, some enums really do want to be exhaustive: Foundation.ComparisonResult, 
Swift.Optional, and in general anything the framework owner really does want 
people to exhaustively switch over. These aren't just optimization concerns 
because they affect how people are expected to use the type. I think this all 
just means that you're on the side that "open" should be the default.


> 
> Btw, is open enum is allowed to change the type of associated value for some 
> cases or even enum's raw type? I.e. what changes in open enum will lead to 
> crash in our code and which will just be processed in 'default'/'future' 
> block in switch?

Nope, that's not planned to be allowed. That would break source compatibility 
outside of just switch—it would also affect `if case` as well as the creation 
of an enum with that case.

The last time I thought about this, I came up with this list of things we want 
to allow in "open" enums:

• Adding a new case.
• Reordering existing cases is a "binary-compatible source-breaking 
change". In particular, if an enum is RawRepresentable, changing the raw 
representations of cases may break existing clients who use them for 
serialization.
• Adding a raw type to an enum that does not have one.
• Removing a non-public, non-versioned case (if we ever have such a 
thing).
• Adding any other members.
• Removing any non-public, non-versioned members.
• Adding a new protocol conformance (with proper annotations).
• Removing conformances to non-public protocols.

We're now questioning whether reordering should be allowed at all for 
implementation reasons, but other than that this list should still be accurate.

> 
> Vladimir. (P.S. Sorry for long reply)

Thanks for thinking about this in detail; better to get the problems out in the 
open now before I write up a formal proposal!

Jordan

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


Re: [swift-evolution] Enums and Source Compatibility

2017-08-11 Thread Vladimir.S via swift-evolution

On 11.08.2017 2:37, Jordan Rose wrote:
Both you and Vladimir are bringing up this point, with Vladimir explicitly suggesting 
a "future" case that's different from "default". Again, the pushback we get here is 
that the "future" case is untestable…but maybe that's still an option worth having. 


I wonder, how the 'default' in exhaustive switch on open enum is testable?

I mean, let's say we have such enum in one of the frameworks:

open enum MyOpenEnum {
  case one
  case two
}

, then in our code:

switch myOpenEnumInstance {
  case .one : ...
  case .two : ...
  default : ... // how this can be tested?
}

I just strongly feel that be able to keep switch exhaustive at the moment of 
compilation - is critical requirement in some cases, when it is very important to not 
forget to process some cases. With just 'default' in switch for open enum - we are 
loosing this compiler's help. This is why 'future' case is required for open enums.


Also, if I understand correctly, we are going to have most of all extern(imported) 
enums as 'open'. So, we are loosing the feature to receive a help for exhaustive 
switch from compiler for most of such enums.


Moreover, shouldn't we just say that enums, that we have no Swift sources for at the 
moment of compilation - should *always* be treated as 'open'? If we compile our 
'switch' together with the source of switched enum - such enum can not be changed in 
the future.
But, if enum is coming from other framework - we have no any control over it, and 
even author of framework IMO can't be sure in most cases that enum will not be 
extended in future, and probably we even should not ask author of framework to 
consider its enum closed, as most likely one can't foresee for sure.


Wouldn't this be a simpler and more robust model to think about enums in Swift?
So you know, that *any* enum coming from framework(not from source) - can be changed 
in future, and so you have to process this case explicitly. In this case we don't 
need to mark enum as 'open' or 'closed' at all, but for some rare cases, when author 
of framework *really sure* enum can not be changed in future(and future change in 
enum will break all the code depending on it), we can introduce some 'final' 
marker(or @exhaustive directive) to help compiler's optimizations.


Btw, is open enum is allowed to change the type of associated value for some cases or 
even enum's raw type? I.e. what changes in open enum will lead to crash in our code 
and which will just be processed in 'default'/'future' block in switch?


Vladimir. (P.S. Sorry for long reply)

(At the very least, it's worth recording in any eventual proposal why we /don't/ have 
it, and it could be added later if it turns out that was wrong.)


Thank you both for pushing on it.

Jordan


On Aug 9, 2017, at 21:55, Charlie Monroe > wrote:


Hi Jordan,

let's say I'm writing my custom number formatter and I switch 
over NSNumberFormatterStyle (NumberFormatter.Style in Swift) - the question always 
is what to do with the default case - it's a value that I am not programmatically 
counting with. I would personally just put in fatalError with a description that it 
was passed an unhandled style. Listing all enums in Foundation, I can see using 
most of them this way.


I personally have most of my switches exhaustive, mainly for the sake of being 
warned/error'ed when a new case is introduced - I've just done a quick search 
through my projects and I use default: usually for switching over non-enums 
(strings, object matching, ints, ...).


Maybe I'm in the minority here... Seemed like a good practice to me - usually the 
enum doesn't have but a few items on the list and you usually don't handle just 1-2 
cases in your switch, which makes the default label save you 1-2 lines of code that 
can save you from unnnecessarily crashing during runtime...


On Aug 10, 2017, at 1:57 AM, Jordan Rose > wrote:


Hi, Charlie. This is fair—if you're switching over an open enum at all, presumably 
you have a reason for doing so and therefore might want to handle all known cases 
every time you update your SDK. However, I think in practice that's going to be 
rare—do you have examples of exhaustive switches on SDK enums that exist in your 
own app?


(There's an additional piece about how to handle cases with different 
availability—there's nowhere obvious to write the #available.)


I suspect marking SDK enums "closed" will be much easier than nullability, simply 
because there are so few of them. Here's some data to that effect: out of all  60 
or so NS_ENUMs in Foundation, only 6 of them are ones I would definitely mark 
"closed":


- NSComparisonResult
- NSKeyValueChange / NSKeyValueSetMutationKind
- NSRectEdge
- NSURLRelationship
- /maybe/ NSCalculationError

There are a few more, like NSURLHandleStatus, where I could see someone wanting to 
exhaustively 

Re: [swift-evolution] Enums and Source Compatibility - defaults

2017-08-10 Thread Jordan Rose via swift-evolution


> On Aug 10, 2017, at 13:00, David Hart  wrote:
> 
> 
> 
> On 10 Aug 2017, at 19:19, Jordan Rose  > wrote:
> 
>> 
>> 
>>> On Aug 9, 2017, at 22:46, David Hart >> > wrote:
>>> 
>>> 
 On 10 Aug 2017, at 02:42, Jordan Rose > wrote:
 
 :-) As you've all noted, there are some conflicting concerns for the 
 default:
 
 - Source compatibility: the existing behavior for an unannotated enum is 
 "closed".
 - Intuition: if you show someone an enum without an explicit annotation, 
 they'll probably expect they can switch over it. (I'm going to say this is 
 why Zach calls it a "sensible default".)
 - Consistency: switches on an enum in the same module can always be 
 exhaustive, so having it be different across modules is a bit annoying. 
 (But 'public' already acts like this.)
 
 vs.
 
 - Library evolution: the default should promise less, so that you have the 
 opportunity to change it.
 - Flexibility: you can emulate an exhaustive switch with a non-exhaustive 
 switch using fatalError, but not the other way around.
 
 All of this is why I suggested it be an explicit annotation in either 
 direction, but Matthew brought up the "keyword soup" problem—if you have 
 to write (say) "public finite enum" and "public infinite enum", but would 
 never write "private finite enum" or "private infinite enum", something is 
 redundant here. Still, I'm uncomfortable with the default case being the 
 one that constrains library authors, so at least for binary frameworks 
 (those compiled "with resilience") I would want that to be explicit. That 
 brings us to one more concern: how different should binary frameworks be 
 from source frameworks?
>>> 
>>> In terms of intuition and consistency, I think we should really try to 
>>> learn from the simplicity of public/open:
>>> 
>>> * When internal, classes are sub-classable by default for convenience, but 
>>> can be closed with the final keyword
>>> * When public, classes are closed to sub-classing for safety, but can be 
>>> opened up with the open keyword (which implies public).
>>> 
>>> If we try to mirror this behaviour (the keywords are just suggestions, not 
>>> important):
>>> 
>>> * When internal, enums are exhaustive by default for convenience, but can 
>>> be opened-up with the partial keyword
>>> * When public, enums are non-exhaustive by default for safety, but can be 
>>> made exhaustive with the exhaustive keyword (which implies public).
>> 
>> This is not a correct understanding of the internal/public distinction for 
>> classes, though. From inside a module, a public-but-not-open class is still 
>> subclassable, and similarly a public-but-not-"closed" enum will still be 
>> exhaustively switched. You don't have to worry about your own module 
>> changing out from under you.
> 
> Correct. Thanks for the clarification! But you still agree with the argument, 
> right? Convenience for same module enums (exhaustive by default), safety for 
> clients of the module (not-exhaustive when public from outside the module), 
> with the option to be explicit?

That's the "library evolution" criterion above, yes. But the behavior of enums 
inside the module doesn't need to affect what we do across modules.

> And what do you think of the idea of having the « exhaustiveness » modifier 
> imply public, like open does?

I'm a little less sure about that. It does help with the keyword soup problem, 
but it's also not as obviously about access as "open" was, and "open" can also 
appear where other access modifiers can appear (on methods, properties, and 
subscripts).

Jordan

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


  1   2   >