Handling unknown cases in enums [RE: SE-0192]

I think `unknown` should be a modifier for either `case` or `default`. This would allow:

  unknown default:
  unknown case _: // similar to default
  unknown case (1, _): // enum in second position

If the case can be reached with statically known enum values, the compiler generates a warning.

I'd also prefer a more precise term instead of "unknown". What we aim at is matching cases that do not have a declaration (future cases, privately-declared cases). So I'd use the word "undeclared" rather than "unknown":

  undeclared default:
  undeclared case _: // similar to default
  undeclared case (1, _): // enum in second position

That word has the advantage that enums are also less likely to have a case named "undeclared", I think.

···

Le 10 janv. 2018 à 23:31, Chris Lattner via swift-evolution <swift-evolution@swift.org> a écrit :

On Jan 10, 2018, at 10:10 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

- Matching known cases is a feature, not a limitation, to avoid existing code changing meaning when you recompile. I'll admit that's not the strongest motivation, though, since other things can change the meaning of existing code when you recompile already.

I’m not sure I understand this.

The whole motivation for this feature is to notify people if they are not handling a “newly known” case. If they don’t care about this, they can just use default.

Notify, yes. Error, no. It's a design goal that adding a new case does not break source compatibility in addition to not breaking binary compatibility (because people don't like editing their dependencies) and therefore the behavior has to be defined when they recompile with no changes.

Ok, if that’s the desired design, then (IMO) the right way to spell it is “unknown default:” and it should have semantics basically aligned with the design you laid out in the revision of the proposal. If this is supposed to be an error, then it should be a pattern production.

Do you have a sense for whether this is what people want? We really should have a review cycle evaluating exactly this sort of tradeoff.

In any case, I’ve said this before off-list, but I find this whole discussion (of how to improve diagnostics for unknown cases) to be separable from the core issue required to get to ABI stability. It seems to me that we could split this (ongoing) design discussion off into a separate SE, allowing you to get on with the relatively uncontroversial and critical parts in SE-0192.

-Chris

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

--
Michel Fortin
https://michelf.ca

Two points:

1. I like Chris’s suggestion of #unknown and in particular that it is distinct from default.

2. All the discussion is about a framework adding a case, what about when a framework deletes a case?

-- Howard.

···

On 10 Jan 2018, at 1:41 pm, Dave DeLong via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 10, 2018, at 1:29 PM, Dave DeLong via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 10, 2018, at 1:05 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

That said, it sounds like people are happier with `case #unknown` than `unknown case`, and that leaves things a little more consistent if we ever do expand it to other pattern positions, so I'll change the proposal revision to use that spelling. (And if anyone comes up with a nicer spelling, great!)

Thanks!

Updated! https://github.com/apple/swift-evolution/pull/777. Also tried to clarify some of the points on why I'm leery about #unknown as an arbitrary pattern, at least for now.

Hi Jordan,

After a long and hard reading, I will conditionally +1 this:

I agree that this is a problem that “needs" to be solved. (“Needs” is subjective, because as you correctly point out, there are other languages that don’t do this and seem to be relatively OK with that)
I am ok with the @frozen moniker on enums
I am ok with the “#unknown” syntax
I am therefore generally ok with the proposed solution

BUT:

I think the application of the warnings is still overly broad. The frozenness of an enum is only a problem for enums that come from dynamically linked modules that are external to my built project.

Therefore I’d like to see stuff regarding:

future directions for how we can refine the behavior and tooling around frozen enums, specifically
“statically” linking libraries (ie, the “import Module1 @ 12.1.2” stuff, aka “version locking"), because statically linking should eliminate frozenness concerns
embedded modules not producing warnings in the future, because embedded modules only change when the app author decides
ruminations on improving tooling for yelling at a developer if they “unfreeze” an enum in between versions (ie, a reduction of the SemVer conversation)

Because version locking and knowledge of embedding modules doesn’t currently exist, we’re forced to deal with the over-applicability of frozenness that shouldn’t be necessary. Getting those in would go a long way towards getting this feature scoped down to where it properly belongs in the app development workflow.

In other words, the current solution will produce a bunch of false positives, and I’d like to see stuff in the proposal about how those false positives will be addressed.

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

1 Like

I think `unknown` should be a modifier for either `case` or `default`. This would allow:

  unknown default:
  unknown case _: // similar to default
  unknown case (1, _): // enum in second position

If the case can be reached with statically known enum values, the compiler generates a warning.

I'd also prefer a more precise term instead of "unknown". What we aim at is matching cases that do not have a declaration (future cases, privately-declared cases). So I'd use the word "undeclared" rather than "unknown":

  undeclared default:
  undeclared case _: // similar to default
  undeclared case (1, _): // enum in second position

That word has the advantage that enums are also less likely to have a case named "undeclared", I think.

I’m not sure I’d agree that most people would think of private cases are “undeclared”, but sure, it’s a reasonable alternative. I still like “unknown” a little better myself.

Jordan

···

On Jan 11, 2018, at 05:08, Michel Fortin <michel.fortin@michelf.ca> wrote:

Le 10 janv. 2018 à 23:31, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Jan 10, 2018, at 10:10 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

- Matching known cases is a feature, not a limitation, to avoid existing code changing meaning when you recompile. I'll admit that's not the strongest motivation, though, since other things can change the meaning of existing code when you recompile already.

I’m not sure I understand this.

The whole motivation for this feature is to notify people if they are not handling a “newly known” case. If they don’t care about this, they can just use default.

Notify, yes. Error, no. It's a design goal that adding a new case does not break source compatibility in addition to not breaking binary compatibility (because people don't like editing their dependencies) and therefore the behavior has to be defined when they recompile with no changes.

Ok, if that’s the desired design, then (IMO) the right way to spell it is “unknown default:” and it should have semantics basically aligned with the design you laid out in the revision of the proposal. If this is supposed to be an error, then it should be a pattern production.

Do you have a sense for whether this is what people want? We really should have a review cycle evaluating exactly this sort of tradeoff.

In any case, I’ve said this before off-list, but I find this whole discussion (of how to improve diagnostics for unknown cases) to be separable from the core issue required to get to ABI stability. It seems to me that we could split this (ongoing) design discussion off into a separate SE, allowing you to get on with the relatively uncontroversial and critical parts in SE-0192.

-Chris

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

--
Michel Fortin
https://michelf.ca <https://michelf.ca/>

This is a binary breaking change (just like removing an existing function or method).

···

Le 10 janv. 2018 à 23:58, Howard Lovatt via swift-evolution <swift-evolution@swift.org> a écrit :

Two points:

1. I like Chris’s suggestion of #unknown and in particular that it is distinct from default.

2. All the discussion is about a framework adding a case, what about when a framework deletes a case?

Well if you are happy to say removal of a case isn’t allowed, why not be symmetrical and say adding isn’t allowed and if an API would like to add cases then it needs to do so via adding an extended enum, e.g.:

    enum Old {
        case old1, old2
    }
    enum New {
        case old1 // Note missing old2.
        case new1
    }
    struct Ex {
        func f(old: Old) -> Old { ... }
        func f(new: New) -> New { ... }
    }

If this approach is taken then it is more work for Apple and less work for developers and a cleaner Swift. So overall it might be the best approach.

-- Howard.

···

On 11 Jan 2018, at 11:23 am, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 11, 2018, at 05:08, Michel Fortin <michel.fortin@michelf.ca> wrote:

I think `unknown` should be a modifier for either `case` or `default`. This would allow:

  unknown default:
  unknown case _: // similar to default
  unknown case (1, _): // enum in second position

If the case can be reached with statically known enum values, the compiler generates a warning.

I'd also prefer a more precise term instead of "unknown". What we aim at is matching cases that do not have a declaration (future cases, privately-declared cases). So I'd use the word "undeclared" rather than "unknown":

  undeclared default:
  undeclared case _: // similar to default
  undeclared case (1, _): // enum in second position

That word has the advantage that enums are also less likely to have a case named "undeclared", I think.

I’m not sure I’d agree that most people would think of private cases are “undeclared”, but sure, it’s a reasonable alternative. I still like “unknown” a little better myself.

Jordan

Le 10 janv. 2018 à 23:31, Chris Lattner via swift-evolution <swift-evolution@swift.org> a écrit :

On Jan 10, 2018, at 10:10 AM, Jordan Rose <jordan_rose@apple.com> wrote:

- Matching known cases is a feature, not a limitation, to avoid existing code changing meaning when you recompile. I'll admit that's not the strongest motivation, though, since other things can change the meaning of existing code when you recompile already.

I’m not sure I understand this.

The whole motivation for this feature is to notify people if they are not handling a “newly known” case. If they don’t care about this, they can just use default.

Notify, yes. Error, no. It's a design goal that adding a new case does not break source compatibility in addition to not breaking binary compatibility (because people don't like editing their dependencies) and therefore the behavior has to be defined when they recompile with no changes.

Ok, if that’s the desired design, then (IMO) the right way to spell it is “unknown default:” and it should have semantics basically aligned with the design you laid out in the revision of the proposal. If this is supposed to be an error, then it should be a pattern production.

Do you have a sense for whether this is what people want? We really should have a review cycle evaluating exactly this sort of tradeoff.

In any case, I’ve said this before off-list, but I find this whole discussion (of how to improve diagnostics for unknown cases) to be separable from the core issue required to get to ABI stability. It seems to me that we could split this (ongoing) design discussion off into a separate SE, allowing you to get on with the relatively uncontroversial and critical parts in SE-0192.

-Chris

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

--
Michel Fortin
https://michelf.ca

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

Remember, the goal here is to support both binary and source compatibility. An existing app might be using the enum case that you're trying to remove, but there's no chance that an existing app is using an enum case that you're trying to add.

Jordan

···

On Jan 10, 2018, at 16:34, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

If an enum isn’t final; then what’s the difference in deleting as opposed to adding?

-- Howard.

On 10 Jan 2018, at 4:13 pm, Jean-Daniel <mailing@xenonium.com> wrote:

Le 10 janv. 2018 à 23:58, Howard Lovatt via swift-evolution <swift-evolution@swift.org> a écrit :

Two points:

1. I like Chris’s suggestion of #unknown and in particular that it is distinct from default.

2. All the discussion is about a framework adding a case, what about when a framework deletes a case?

This is a binary breaking change (just like removing an existing function or method).

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

If an enum isn’t final; then what’s the difference in deleting as opposed to adding?

-- Howard.

···

On 10 Jan 2018, at 4:13 pm, Jean-Daniel <mailing@xenonium.com> wrote:

Le 10 janv. 2018 à 23:58, Howard Lovatt via swift-evolution <swift-evolution@swift.org> a écrit :

Two points:

1. I like Chris’s suggestion of #unknown and in particular that it is distinct from default.

2. All the discussion is about a framework adding a case, what about when a framework deletes a case?

This is a binary breaking change (just like removing an existing function or method).

It is a two way street though. An app compiled against an old framework might pass a deleted enum case back to the new framework that has been changed under it.

Just as the app has to guard against new cases the framework has to guard against old cases!

Both ends need an unknown case.

-- Howard.

···

On 10 Jan 2018, at 5:40 pm, Jordan Rose <jordan_rose@apple.com> wrote:

Remember, the goal here is to support both binary and source compatibility. An existing app might be using the enum case that you're trying to remove, but there's no chance that an existing app is using an enum case that you're trying to add.

Jordan

On Jan 10, 2018, at 16:34, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

If an enum isn’t final; then what’s the difference in deleting as opposed to adding?

-- Howard.

On 10 Jan 2018, at 4:13 pm, Jean-Daniel <mailing@xenonium.com> wrote:

Le 10 janv. 2018 à 23:58, Howard Lovatt via swift-evolution <swift-evolution@swift.org> a écrit :

Two points:

1. I like Chris’s suggestion of #unknown and in particular that it is distinct from default.

2. All the discussion is about a framework adding a case, what about when a framework deletes a case?

This is a binary breaking change (just like removing an existing function or method).

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

Let say you have a module that declare a enum and also declare a function that take that enum as parameter and switch over it.

As there is no cross module boundary, the switch don’t require #unknown or any fancy trick to be exhaustive.

Now if you remove the case from the enum, any client code that call your function by passing the enum will cause a crash.

The following is just blind guess as I don’t have any knowledge of the swift compiler, but as Swift cases are not necessarily simple Int, maybe there some times swift has to generates symbols for complex cases.
In such case, removing an enum will be even more harmful as it will cause a crash a start for missing symbol (assuming at such time Apple did switch to dyld3 which bound at launch and not lazily).

···

Le 11 janv. 2018 à 01:34, Howard Lovatt <howard.lovatt@gmail.com> a écrit :

If an enum isn’t final; then what’s the difference in deleting as opposed to adding?

-- Howard.

On 10 Jan 2018, at 4:13 pm, Jean-Daniel <mailing@xenonium.com> wrote:

Le 10 janv. 2018 à 23:58, Howard Lovatt via swift-evolution <swift-evolution@swift.org> a écrit :

Two points:

1. I like Chris’s suggestion of #unknown and in particular that it is distinct from default.

2. All the discussion is about a framework adding a case, what about when a framework deletes a case?

This is a binary breaking change (just like removing an existing function or method).

Removing cases just isn’t allowed. They can be deprecated, but actually removing one is a breaking change. With a Swift enum the app will actually fail to launch with a dynamic linking error.

Jordan

···

On Jan 10, 2018, at 21:27, Howard Lovatt <howard.lovatt@gmail.com> wrote:

It is a two way street though. An app compiled against an old framework might pass a deleted enum case back to the new framework that has been changed under it.

Just as the app has to guard against new cases the framework has to guard against old cases!

Both ends need an unknown case.

-- Howard.

On 10 Jan 2018, at 5:40 pm, Jordan Rose <jordan_rose@apple.com> wrote:

Remember, the goal here is to support both binary and source compatibility. An existing app might be using the enum case that you're trying to remove, but there's no chance that an existing app is using an enum case that you're trying to add.

Jordan

On Jan 10, 2018, at 16:34, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

If an enum isn’t final; then what’s the difference in deleting as opposed to adding?

-- Howard.

On 10 Jan 2018, at 4:13 pm, Jean-Daniel <mailing@xenonium.com> wrote:

Le 10 janv. 2018 à 23:58, Howard Lovatt via swift-evolution <swift-evolution@swift.org> a écrit :

Two points:

1. I like Chris’s suggestion of #unknown and in particular that it is distinct from default.

2. All the discussion is about a framework adding a case, what about when a framework deletes a case?

This is a binary breaking change (just like removing an existing function or method).

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

Going that way, we can also deny addition of new members in a struct.

Moreover, while you think that only Apple is interested in having binary stability, this is far to be true, and Apple OSes are not the only OS where Swift can be used.

···

Le 12 janv. 2018 à 02:48, Howard Lovatt via swift-evolution <swift-evolution@swift.org> a écrit :

Well if you are happy to say removal of a case isn’t allowed, why not be symmetrical and say adding isn’t allowed and if an API would like to add cases then it needs to do so via adding an extended enum, e.g.:

    enum Old {
        case old1, old2
    }
    enum New {
        case old1 // Note missing old2.
        case new1
    }
    struct Ex {
        func f(old: Old) -> Old { ... }
        func f(new: New) -> New { ... }
    }

If this approach is taken then it is more work for Apple and less work for developers and a cleaner Swift. So overall it might be the best approach.

-- Howard.

On 11 Jan 2018, at 11:23 am, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 11, 2018, at 05:08, Michel Fortin <michel.fortin@michelf.ca <mailto:michel.fortin@michelf.ca>> wrote:

I think `unknown` should be a modifier for either `case` or `default`. This would allow:

  unknown default:
  unknown case _: // similar to default
  unknown case (1, _): // enum in second position

If the case can be reached with statically known enum values, the compiler generates a warning.

I'd also prefer a more precise term instead of "unknown". What we aim at is matching cases that do not have a declaration (future cases, privately-declared cases). So I'd use the word "undeclared" rather than "unknown":

  undeclared default:
  undeclared case _: // similar to default
  undeclared case (1, _): // enum in second position

That word has the advantage that enums are also less likely to have a case named "undeclared", I think.

I’m not sure I’d agree that most people would think of private cases are “undeclared”, but sure, it’s a reasonable alternative. I still like “unknown” a little better myself.

Jordan

Le 10 janv. 2018 à 23:31, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Jan 10, 2018, at 10:10 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

- Matching known cases is a feature, not a limitation, to avoid existing code changing meaning when you recompile. I'll admit that's not the strongest motivation, though, since other things can change the meaning of existing code when you recompile already.

I’m not sure I understand this.

The whole motivation for this feature is to notify people if they are not handling a “newly known” case. If they don’t care about this, they can just use default.

Notify, yes. Error, no. It's a design goal that adding a new case does not break source compatibility in addition to not breaking binary compatibility (because people don't like editing their dependencies) and therefore the behavior has to be defined when they recompile with no changes.

Ok, if that’s the desired design, then (IMO) the right way to spell it is “unknown default:” and it should have semantics basically aligned with the design you laid out in the revision of the proposal. If this is supposed to be an error, then it should be a pattern production.

Do you have a sense for whether this is what people want? We really should have a review cycle evaluating exactly this sort of tradeoff.

In any case, I’ve said this before off-list, but I find this whole discussion (of how to improve diagnostics for unknown cases) to be separable from the core issue required to get to ABI stability. It seems to me that we could split this (ongoing) design discussion off into a separate SE, allowing you to get on with the relatively uncontroversial and critical parts in SE-0192.

-Chris

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

--
Michel Fortin
https://michelf.ca <https://michelf.ca/>

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

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

A question about the new #unknown behavior. Is it intended to be used for error handling too ?
Will it be possible to use in catch clause ?

···

Le 12 janv. 2018 à 02:48, Howard Lovatt via swift-evolution <swift-evolution@swift.org> a écrit :

Well if you are happy to say removal of a case isn’t allowed, why not be symmetrical and say adding isn’t allowed and if an API would like to add cases then it needs to do so via adding an extended enum, e.g.:

    enum Old {
        case old1, old2
    }
    enum New {
        case old1 // Note missing old2.
        case new1
    }
    struct Ex {
        func f(old: Old) -> Old { ... }
        func f(new: New) -> New { ... }
    }

If this approach is taken then it is more work for Apple and less work for developers and a cleaner Swift. So overall it might be the best approach.

-- Howard.

On 11 Jan 2018, at 11:23 am, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 11, 2018, at 05:08, Michel Fortin <michel.fortin@michelf.ca <mailto:michel.fortin@michelf.ca>> wrote:

I think `unknown` should be a modifier for either `case` or `default`. This would allow:

  unknown default:
  unknown case _: // similar to default
  unknown case (1, _): // enum in second position

If the case can be reached with statically known enum values, the compiler generates a warning.

I'd also prefer a more precise term instead of "unknown". What we aim at is matching cases that do not have a declaration (future cases, privately-declared cases). So I'd use the word "undeclared" rather than "unknown":

  undeclared default:
  undeclared case _: // similar to default
  undeclared case (1, _): // enum in second position

That word has the advantage that enums are also less likely to have a case named "undeclared", I think.

I’m not sure I’d agree that most people would think of private cases are “undeclared”, but sure, it’s a reasonable alternative. I still like “unknown” a little better myself.

Jordan

Le 10 janv. 2018 à 23:31, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Jan 10, 2018, at 10:10 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

- Matching known cases is a feature, not a limitation, to avoid existing code changing meaning when you recompile. I'll admit that's not the strongest motivation, though, since other things can change the meaning of existing code when you recompile already.

I’m not sure I understand this.

The whole motivation for this feature is to notify people if they are not handling a “newly known” case. If they don’t care about this, they can just use default.

Notify, yes. Error, no. It's a design goal that adding a new case does not break source compatibility in addition to not breaking binary compatibility (because people don't like editing their dependencies) and therefore the behavior has to be defined when they recompile with no changes.

Ok, if that’s the desired design, then (IMO) the right way to spell it is “unknown default:” and it should have semantics basically aligned with the design you laid out in the revision of the proposal. If this is supposed to be an error, then it should be a pattern production.

Do you have a sense for whether this is what people want? We really should have a review cycle evaluating exactly this sort of tradeoff.

In any case, I’ve said this before off-list, but I find this whole discussion (of how to improve diagnostics for unknown cases) to be separable from the core issue required to get to ABI stability. It seems to me that we could split this (ongoing) design discussion off into a separate SE, allowing you to get on with the relatively uncontroversial and critical parts in SE-0192.

-Chris

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

--
Michel Fortin
https://michelf.ca <https://michelf.ca/>

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

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

If we go with the #unknown approach, then yes of course it will work in catch clauses. They are patterns, so it naturally falls out.

If we go with the “unknown default:” / “unknown case:" approach, then no, this has nothing to do with error handling.

IMO, this pivots on the desired semantics for “unknown cases in enums”: if you intentionally try to match on this, do we get a warning or error if you don’t handle all the cases? If we can get to consensus on that point, then the design is pretty obvious IMO.

-Chris

···

On Jan 11, 2018, at 11:15 PM, Jean-Daniel via swift-evolution <swift-evolution@swift.org> wrote:

A question about the new #unknown behavior. Is it intended to be used for error handling too ?
Will it be possible to use in catch clause ?

A question about the new #unknown behavior. Is it intended to be used for error handling too ?
Will it be possible to use in catch clause ?

If we go with the #unknown approach, then yes of course it will work in catch clauses. They are patterns, so it naturally falls out.

It will not work in catch clauses because you need to have a static type that's an enum. Catch clauses always (today…) have a static type of 'Error'.

If we go with the “unknown default:” / “unknown case:" approach, then no, this has nothing to do with error handling.

IMO, this pivots on the desired semantics for “unknown cases in enums”: if you intentionally try to match on this, do we get a warning or error if you don’t handle all the cases? If we can get to consensus on that point, then the design is pretty obvious IMO.

That's fair. I'm strongly in favor of a warning, though, because again, people don't edit their dependencies.

Jordan

···

On Jan 11, 2018, at 23:30, Chris Lattner <clattner@nondot.org> wrote:

On Jan 11, 2018, at 11:15 PM, Jean-Daniel via swift-evolution <swift-evolution@swift.org> wrote:

A question about the new #unknown behavior. Is it intended to be used for error handling too ?
Will it be possible to use in catch clause ?

If we go with the #unknown approach, then yes of course it will work in catch clauses. They are patterns, so it naturally falls out.

If we go with the “unknown default:” / “unknown case:" approach, then no, this has nothing to do with error handling.

IMO, this pivots on the desired semantics for “unknown cases in enums”: if you intentionally try to match on this, do we get a warning or error if you don’t handle all the cases? If we can get to consensus on that point, then the design is pretty obvious IMO.

For me the other question is what "all the cases" means for enum with private cases(if we'll have them). I.e. if switch contains all the "public" cases of frozen enum - does this mean "all the cases" were processed? As I understand, the answer is no, because we *can* have 'private' case value here and so we need to react to this. How switch will look in this case?

switch frozenEnumWithPrivateCases {
   case .one: ..
   case .two: ..
   unknown default: .. // or 'case #unknown:' depending on our decision, or 'unknown case:' etc
}
?
But then such switch looks exactly as switch for non-frozen enum value, no? It looks like we are reacting on future new cases, while enum is frozen.

Moreover. How the switch for non-frozed enum with private cases should looks like?

switch nonfrozenEnumWithPrivateCases {
   case .one: ..
   case .two: ..
   unknown default: .. // or 'case #unknown:' depending on our decision, or 'unknown case:' etc
}
? But then, is that 'unknown default' for reacting on "future" cases we didn't know about during the compilation OR it is for reacting on private cases?

Or the main idea that we don't want to separate "future" cases and "private" cases? Then still the first 'switch' on frozen enum confuses the reader.

I understand that we are not discussing the 'private' cases yet, but IMO we should consider how new 'case #unknown/unknown default' will be used in case we'll add that feature.

Vladimir.

···

On 12.01.2018 10:30, Chris Lattner via swift-evolution wrote:

On Jan 11, 2018, at 11:15 PM, Jean-Daniel via swift-evolution <swift-evolution@swift.org> wrote:

-Chris

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

Okay, I went back to `unknown case` in the proposal, but mentioned Chris's point very specifically: if the compiler emits an error, we should go with `case #unknown` instead. (I'm very strongly in the "warning" camp, though.)

I think the revised proposal is in good shape! (https://github.com/apple/swift-evolution/pull/777) I think I've addressed everyone's feedback either in the proposal or on-list, if not necessarily convinced them. If there are no other major comments I'll let Ted know that it's ready to re-run on Monday.

Jordan

I think treating both as the same thing is the right idea. You also need to handle "future private" cases and "private cases that become public in the future". These are all unknown cases in the context of the switch.

So an enum with private cases can't be switched exhaustively outside of its module. Thus, @frozen would need to forbid private cases... or we need @exhaustive to forbid private cases so they can be allowed by @frozen.

···

Le 12 janv. 2018 à 4:44, Vladimir.S via swift-evolution <swift-evolution@swift.org> a écrit :

On 12.01.2018 10:30, Chris Lattner via swift-evolution wrote:

On Jan 11, 2018, at 11:15 PM, Jean-Daniel via swift-evolution <swift-evolution@swift.org> wrote:

A question about the new #unknown behavior. Is it intended to be used for error handling too ?
Will it be possible to use in catch clause ?

If we go with the #unknown approach, then yes of course it will work in catch clauses. They are patterns, so it naturally falls out.
If we go with the “unknown default:” / “unknown case:" approach, then no, this has nothing to do with error handling.
IMO, this pivots on the desired semantics for “unknown cases in enums”: if you intentionally try to match on this, do we get a warning or error if you don’t handle all the cases? If we can get to consensus on that point, then the design is pretty obvious IMO.

For me the other question is what "all the cases" means for enum with private cases(if we'll have them). I.e. if switch contains all the "public" cases of frozen enum - does this mean "all the cases" were processed? As I understand, the answer is no, because we *can* have 'private' case value here and so we need to react to this. How switch will look in this case?

switch frozenEnumWithPrivateCases {
case .one: ..
case .two: ..
unknown default: .. // or 'case #unknown:' depending on our decision, or 'unknown case:' etc
}
?
But then such switch looks exactly as switch for non-frozen enum value, no? It looks like we are reacting on future new cases, while enum is frozen.

Moreover. How the switch for non-frozed enum with private cases should looks like?

switch nonfrozenEnumWithPrivateCases {
case .one: ..
case .two: ..
unknown default: .. // or 'case #unknown:' depending on our decision, or 'unknown case:' etc
}
? But then, is that 'unknown default' for reacting on "future" cases we didn't know about during the compilation OR it is for reacting on private cases?

Or the main idea that we don't want to separate "future" cases and "private" cases?

--
Michel Fortin
https://michelf.ca

As mentioned in "Future directions", my recommendation to anyone planning to write a proposal for non-public cases is to go with the former, which would keep it from infecting the design.

Jordan

···

On Jan 12, 2018, at 06:49, Michel Fortin via swift-evolution <swift-evolution@swift.org> wrote:

Le 12 janv. 2018 à 4:44, Vladimir.S via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On 12.01.2018 10:30, Chris Lattner via swift-evolution wrote:

On Jan 11, 2018, at 11:15 PM, Jean-Daniel via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

A question about the new #unknown behavior. Is it intended to be used for error handling too ?
Will it be possible to use in catch clause ?

If we go with the #unknown approach, then yes of course it will work in catch clauses. They are patterns, so it naturally falls out.
If we go with the “unknown default:” / “unknown case:" approach, then no, this has nothing to do with error handling.
IMO, this pivots on the desired semantics for “unknown cases in enums”: if you intentionally try to match on this, do we get a warning or error if you don’t handle all the cases? If we can get to consensus on that point, then the design is pretty obvious IMO.

For me the other question is what "all the cases" means for enum with private cases(if we'll have them). I.e. if switch contains all the "public" cases of frozen enum - does this mean "all the cases" were processed? As I understand, the answer is no, because we *can* have 'private' case value here and so we need to react to this. How switch will look in this case?

switch frozenEnumWithPrivateCases {
case .one: ..
case .two: ..
unknown default: .. // or 'case #unknown:' depending on our decision, or 'unknown case:' etc
}
?
But then such switch looks exactly as switch for non-frozen enum value, no? It looks like we are reacting on future new cases, while enum is frozen.

Moreover. How the switch for non-frozed enum with private cases should looks like?

switch nonfrozenEnumWithPrivateCases {
case .one: ..
case .two: ..
unknown default: .. // or 'case #unknown:' depending on our decision, or 'unknown case:' etc
}
? But then, is that 'unknown default' for reacting on "future" cases we didn't know about during the compilation OR it is for reacting on private cases?

Or the main idea that we don't want to separate "future" cases and "private" cases?

I think treating both as the same thing is the right idea. You also need to handle "future private" cases and "private cases that become public in the future". These are all unknown cases in the context of the switch.

So an enum with private cases can't be switched exhaustively outside of its module. Thus, @frozen would need to forbid private cases... or we need @exhaustive to forbid private cases so they can be allowed by @frozen.

A question about the new #unknown behavior. Is it intended to be used for error handling too ?
Will it be possible to use in catch clause ?

If we go with the #unknown approach, then yes of course it will work in catch clauses. They are patterns, so it naturally falls out.

It will not work in catch clauses because you need to have a static type that's an enum. Catch clauses always (today…) have a static type of 'Error'.

Right, although it should work for enum Error types in catch clauses if we add typed errors in the future. That’s worth considering when making this decision.

···

Sent from my iPad

On Jan 12, 2018, at 12:25 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 11, 2018, at 23:30, Chris Lattner <clattner@nondot.org> wrote:

On Jan 11, 2018, at 11:15 PM, Jean-Daniel via swift-evolution <swift-evolution@swift.org> wrote:

If we go with the “unknown default:” / “unknown case:" approach, then no, this has nothing to do with error handling.

IMO, this pivots on the desired semantics for “unknown cases in enums”: if you intentionally try to match on this, do we get a warning or error if you don’t handle all the cases? If we can get to consensus on that point, then the design is pretty obvious IMO.

That's fair. I'm strongly in favor of a warning, though, because again, people don't edit their dependencies.

Jordan

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

Unless I’m missing something, this is still missing the discussion on being able to treat all enums of internally-packaged libraries as frozen.

IE, that frozen vs unfrozen is only an issue for enums that come from modules that are not packaged with your app.

Dave

···

On Jan 12, 2018, at 4:08 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Okay, I went back to `unknown case` in the proposal, but mentioned Chris's point very specifically: if the compiler emits an error, we should go with `case #unknown` instead. (I'm very strongly in the "warning" camp, though.)

I think the revised proposal is in good shape! (https://github.com/apple/swift-evolution/pull/777) I think I've addressed everyone's feedback either in the proposal or on-list, if not necessarily convinced them. If there are no other major comments I'll let Ted know that it's ready to re-run on Monday.

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