Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-05 Thread Cheyo J. Jimenez via swift-evolution

> On Jan 5, 2018, at 4:42 AM, Xiaodi Wu  wrote:
> 
> 
> On Fri, Jan 5, 2018 at 03:11 Jonathan Hull  > wrote:
>> On Jan 4, 2018, at 11:02 PM, Xiaodi Wu > > wrote:
>> 
>> 
>> On Fri, Jan 5, 2018 at 01:56 Jonathan Hull > > wrote:
>>> On Jan 4, 2018, at 10:31 PM, Xiaodi Wu via swift-evolution 
>>> mailto:swift-evolution@swift.org>> wrote:
>> 
>>> 
>>> On Fri, Jan 5, 2018 at 00:21 Cheyo Jimenez >> > wrote:
>> 
>>> 
>>> On Jan 4, 2018, at 4:37 PM, Xiaodi Wu >> > wrote:
>>> 
>> 
 On Thu, Jan 4, 2018 at 19:29 Cheyo J. Jimenez >>> > wrote:
 
 We seem to agree that, by virtue of not supporting use in a pattern and 
 being placed at the end, the feature is a flavor of default. I’m still not 
 sure I understand why you believe it should not be a flavor of default 
 going forward.
 
> 
> You still haven’t answered my question, though—what’s the use case for 
> the feature you propose?
 
 My use case would be distinguishing between compile time known cases vs 
 “future only” cases (or unknown cases).
 
 I understand that the feature you propose would allow you to make such a 
 distinction, but again, what is your use case for doing so?
>> 
>>> Breaking out early by checking unknown cases first. I admit this is not 
>>> deal breaker, just a different style I’d like to see supported in the 
>>> future. 
>> 
>>> 
>>> I'm still not sure I understand. How can the machine know that it's dealing 
>>> with an unknown case without first checking if it matches any known case?
>> 
>> 
>> I had the same thought as Cheyo.  It isn’t a deal breaker… I like the 
>> compromise, but I would prefer it trigger only on an actual unknown case (as 
>> opposed to acting like default). I like to break failure cases out at the 
>> top when possible. I don’t see any good reason not to support that style.
>> 
>> To answer your question, in the naive sense, it basically is the same 
>> question as asking if it is a known case (and then taking the inverse). That 
>> doesn’t mean actually checking each case separately though. For example, if 
>> the enum cases are internally represented as an unsigned integer, and they 
>> are all together in a block, the compiler could simply check that it is 
>> greater than the max known value. You could probably even do a bit mask 
>> comparison in some cases...
>> 
>> These are obvious optimizations, but why does this require new syntax?
> 
> I am not sure I understand what you are asking. There isn’t additional 
> syntax.  We are just arguing over the name + behavior of ‘unexpected:’.  You 
> want it to behave like ‘default’ and I am saying that stops the use case I 
> mention above.
> 
> Cheyo said he wants “unexpected case” to work in pattern matching, as well as 
> a new “case *” that is distinct from “case _”. This is additional syntax. 
> When asked what the use case was for these suggestions, he said he wants to 
> distinguish between known and unknown cases at the beginning of the switch.
> 
> 
> 
>> What do you gain from writing the unknown case first?
> 
> I know where to look for the failure cases.  I also tend put a bunch of guard 
> statements near the beginning of a function.  It is just a programming style.
> 
> With my behavior of ‘unexpected:’ you can put it wherever you want.  Why 
> limit that by forcing it to go at the end?
> 
> As pointed out earlier (by one of the core team members, I think), meaningful 
> resilience would mean that the unexpected or unknown case should have useful 
> work executed at runtime; the intention is that the user *shouldn’t* be 
> treating it as a runtime “failure case,” as it effectively makes adding an 
> enum case a change that is incompatible with existing binaries (i.e., not 
> terribly resilient).
> 
> As you and I seem to agree, reaching an unexpected case requires at least 
> notionally considering which cases are expected in the first place. This is 
> the dictionary definition of a default, and Swift usage is to put the default 
> case at the end of a switch statement. Adding new syntax as Cheyo suggests to 
> enable putting it elsewhere, merely for “style,” doesn’t seem to pass the bar 
> for new syntax, nor is it consistent with existing Swift usage.

I agree with the new syntax suggestion is premature. I would hope that the 
proposed runtime "Deriving collections of enum cases” 
 function also has a 
compile time version which we can then use to match all the known cases at 
compile time. I am happy with SE 0192 as it stands now. 


> 
>> Isn't this basically the same thing as asking for the ability to write the 
>> default case first, a frequently suggested and rejected syntax addition?
> 
> No.  I don’t think I have ever heard that asked for,
> 
> It has been asked for more

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-04 Thread Cheyo J. Jimenez via swift-evolution

> On Jan 4, 2018, at 3:50 PM, Xiaodi Wu  wrote:
> 
> 
> On Thu, Jan 4, 2018 at 18:39 Cheyo J. Jimenez  > wrote:
> 
>> On Jan 4, 2018, at 2:55 PM, Xiaodi Wu > > wrote:
>> 
>> 
>> On Thu, Jan 4, 2018 at 17:15 Cheyo J. Jimenez > > wrote:
>>> On Jan 4, 2018, at 11:53 AM, Xiaodi Wu >> > wrote:
>>> 
>>> 
>>> On Thu, Jan 4, 2018 at 13:46 Cheyo Jimenez >> > wrote:
>>> 
>>> 
>>> On Jan 4, 2018, at 10:49 AM, Jordan Rose >> > wrote:
>>> 
 I'll admit I hadn't thought of using "unknown default" (or "default 
 unknown"). I don't think that's terrible, but I mildly prefer `unknown 
 case` because it builds on the "pun" that enum elements are also defined 
 using 'case'. If anything hits this part of the switch, it really will be 
 an "unknown case", i.e. a statically-unknown enum element.
 
 To Cheyo's point, if this were to be a single token I'd probably spell it 
 #unknown, like #available. Then we'd have `case #unknown:` and something 
 that naturally expands to other pattern positions. I found that less 
 aesthetically pleasing, though, and so a context-sensitive keyword seemed 
 like the way to go.
 
 (For the record, though, I wouldn't describe `case _` as a special case of 
 `default`. They do exactly the same thing, and `_` is a useful pattern in 
 other contexts, so if anything the current `default` should be thought of 
 as syntactic sugar for `case _`.)
>>> 
>>> Can case _ be mixed with unknown case? How can we match all compile time 
>>> known cases but exclude future cases?
>>> 
>>> What’s your use case for that? That eliminates the possibility of “unknown 
>>> case” giving you compile-time warnings for subsequently added cases, which 
>>> was the entire purpose of adding the syntax in the first place.
>> 
>> I was thinking of a generalized `unknown case` pattern but that is out of 
>> scope for this proposal. 
>> 
>>  
>> 
>> switch excuse {
>>  case .eatenByPet :
>>//…
>>  unknown case:
>>// …
>>  case _:
>>// …
>>  }
>> 
>>> 
>>> Should there be something like `case *` that would capture all currently 
>>> known cases during compile time? case * and case _ would be the same in 
>>> exhaustive enums. 
>> 
>> This is why I was suggesting another pattern that only captures known cases 
>> at compile time:
>> 
>> switch excuse {
>>  case .eatenByPet :
>>//…
>>  case * : //  All cases captured at compile time. 
>>// …
>>  unknown case:
>>// …
>>  }
>> 
>> Sorry, I don’t understand. However you spell it, what is your use case for 
>> this? The stated purpose of “unknown case” is to gain compile-time 
>> exhaustiveness testing, but this would not allow for that.
> 
> 
> 
> 
> switch (excuse, notifiedTeacherBeforeDeadline) {
> case (.eatenByPet, true):
>   // …
> case (.thoughtItWasDueNextWeek, true):
>   // …
> case (unknown case, true):
>   // …
> case (_, false):
>   // …
> }
> 
> Im referring to the future direction section in the new PR 
> .
>  The above example if from there. 
> 
> I am fine with `unknown case` being required to be at the end of the switch 
> for now. 
> 
> I think of `unknown case` as a pattern that only matches unknown cases no 
> matter where on the switch it is.
> 
> This is why I do not think that `default unknown` would work well once 
> `unknown case` can be used a pattern.
> 
> We can start a new thread on this if you’d like. 
> 
> The reason I put forward “default unknown” is precisely because the proposed 
> feature *cannot* be used in a pattern and therefore seems more apt as not a 
> case.
> 
It can not be used in a pattern now but you could in the future if left as 
`case`. 

> It actually makes it more natural to use in the given example above because 
> “default unknown” could actually be used to provide compile-time 
> exhaustiveness checking for such a tuple pattern, whereas without being able 
> to use “unknown case” in a pattern you can’t write “case (unknown case, _)”.

The way `unknown case` enforces  compile-time exhaustiveness is by only 
matching unknown cases. The implementation may be more close to default by the 
virtue of being forced to go at the end of the switch statement now but that 
should not dictate the user experience. 

> 
> You still haven’t answered my question, though—what’s the use case for the 
> feature you propose?

My use case would be distinguishing between compile time known cases vs “future 
only” cases (or unknown cases). This depends on generalized `unknown case` 
patterns which is out of scope. I am happy to talk more about this on a 
diffe

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-04 Thread Cheyo J. Jimenez via swift-evolution

> On Jan 4, 2018, at 2:55 PM, Xiaodi Wu  wrote:
> 
> 
> On Thu, Jan 4, 2018 at 17:15 Cheyo J. Jimenez  > wrote:
>> On Jan 4, 2018, at 11:53 AM, Xiaodi Wu > > wrote:
>> 
>> 
>> On Thu, Jan 4, 2018 at 13:46 Cheyo Jimenez > > wrote:
>> 
>> 
>> On Jan 4, 2018, at 10:49 AM, Jordan Rose > > wrote:
>> 
>>> I'll admit I hadn't thought of using "unknown default" (or "default 
>>> unknown"). I don't think that's terrible, but I mildly prefer `unknown 
>>> case` because it builds on the "pun" that enum elements are also defined 
>>> using 'case'. If anything hits this part of the switch, it really will be 
>>> an "unknown case", i.e. a statically-unknown enum element.
>>> 
>>> To Cheyo's point, if this were to be a single token I'd probably spell it 
>>> #unknown, like #available. Then we'd have `case #unknown:` and something 
>>> that naturally expands to other pattern positions. I found that less 
>>> aesthetically pleasing, though, and so a context-sensitive keyword seemed 
>>> like the way to go.
>>> 
>>> (For the record, though, I wouldn't describe `case _` as a special case of 
>>> `default`. They do exactly the same thing, and `_` is a useful pattern in 
>>> other contexts, so if anything the current `default` should be thought of 
>>> as syntactic sugar for `case _`.)
>> 
>> Can case _ be mixed with unknown case? How can we match all compile time 
>> known cases but exclude future cases?
>> 
>> What’s your use case for that? That eliminates the possibility of “unknown 
>> case” giving you compile-time warnings for subsequently added cases, which 
>> was the entire purpose of adding the syntax in the first place.
> 
> I was thinking of a generalized `unknown case` pattern but that is out of 
> scope for this proposal. 
> 
>  
> 
> switch excuse {
>  case .eatenByPet :
>//…
>  unknown case:
>// …
>  case _:
>// …
>  }
> 
>> 
>> Should there be something like `case *` that would capture all currently 
>> known cases during compile time? case * and case _ would be the same in 
>> exhaustive enums. 
> 
> This is why I was suggesting another pattern that only captures known cases 
> at compile time:
> 
> switch excuse {
>  case .eatenByPet :
>//…
>  case * : //  All cases captured at compile time. 
>// …
>  unknown case:
>// …
>  }
> 
> Sorry, I don’t understand. However you spell it, what is your use case for 
> this? The stated purpose of “unknown case” is to gain compile-time 
> exhaustiveness testing, but this would not allow for that.




switch (excuse, notifiedTeacherBeforeDeadline) {
case (.eatenByPet, true):
  // …
case (.thoughtItWasDueNextWeek, true):
  // …
case (unknown case, true):
  // …
case (_, false):
  // …
}

Im referring to the future direction section in the new PR 
.
 The above example if from there. 

I am fine with `unknown case` being required to be at the end of the switch for 
now. 

I think of `unknown case` as a pattern that only matches unknown cases no 
matter where on the switch it is.

This is why I do not think that `default unknown` would work well once `unknown 
case` can be used a pattern.

We can start a new thread on this if you’d like. 

 

> 
> 
> 
>> 
>> 
>>> 
>>> I'll add these points to the "Alternatives Considered" section in the PR 
>>> later today.
>>> 
>>> Jordan
>>> 
>>> 
 On Jan 3, 2018, at 22:56, Xiaodi Wu >>> > wrote:
 
 As has already been said, “case unknown” is source-breaking because it 
 conflicts with any real cases named “unknown”; “\unknown” looks like a key 
 path but isn’t, and I wonder if it would potentially conflict with 
 existing key paths.
 
 In any case, my point was not to bikeshed the “unknown” part, but to ask 
 whether any consideration had been made to have the feature presented as a 
 flavor of default instead of a flavor of case.
 
 On Wed, Jan 3, 2018 at 23:57 Cheyo Jimenez >>> > wrote:
 
 
 On Jan 3, 2018, at 6:52 PM, Xiaodi Wu via swift-evolution 
 mailto:swift-evolution@swift.org>> wrote:
 
> This is a very nice revision. One bikeshedding thought:
> 
> Since "unknown case" is presented as a special kind of "default", can't 
> be mixed with "default", and can't be used in case patterns, why not 
> "default unknown" (or "unknown default") instead of "unknown case"?
 
 `case _ :` is already a special case of default. 
 I’d rather have `case unknown :`
 `unknown case :` is weird because of the order of `case`. 
 
 Another alternative is `case \unknown :`
 `\unknown` would also allow patter

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-04 Thread Cheyo J. Jimenez via swift-evolution

> On Jan 4, 2018, at 11:53 AM, Xiaodi Wu  wrote:
> 
> 
> On Thu, Jan 4, 2018 at 13:46 Cheyo Jimenez  > wrote:
> 
> 
> On Jan 4, 2018, at 10:49 AM, Jordan Rose  > wrote:
> 
>> I'll admit I hadn't thought of using "unknown default" (or "default 
>> unknown"). I don't think that's terrible, but I mildly prefer `unknown case` 
>> because it builds on the "pun" that enum elements are also defined using 
>> 'case'. If anything hits this part of the switch, it really will be an 
>> "unknown case", i.e. a statically-unknown enum element.
>> 
>> To Cheyo's point, if this were to be a single token I'd probably spell it 
>> #unknown, like #available. Then we'd have `case #unknown:` and something 
>> that naturally expands to other pattern positions. I found that less 
>> aesthetically pleasing, though, and so a context-sensitive keyword seemed 
>> like the way to go.
>> 
>> (For the record, though, I wouldn't describe `case _` as a special case of 
>> `default`. They do exactly the same thing, and `_` is a useful pattern in 
>> other contexts, so if anything the current `default` should be thought of as 
>> syntactic sugar for `case _`.)
> 
> Can case _ be mixed with unknown case? How can we match all compile time 
> known cases but exclude future cases?
> 
> What’s your use case for that? That eliminates the possibility of “unknown 
> case” giving you compile-time warnings for subsequently added cases, which 
> was the entire purpose of adding the syntax in the first place.

I was thinking of a generalized `unknown case` pattern but that is out of scope 
for this proposal. 

 

switch excuse {
 case .eatenByPet :
   //…
 unknown case:
   // …
 case _:
   // …
 }

> 
> Should there be something like `case *` that would capture all currently 
> known cases during compile time? case * and case _ would be the same in 
> exhaustive enums. 

This is why I was suggesting another pattern that only captures known cases at 
compile time:

switch excuse {
 case .eatenByPet :
   //…
 case * : //  All cases captured at compile time. 
   // …
 unknown case:
   // …
 }

> 
> 
>> 
>> I'll add these points to the "Alternatives Considered" section in the PR 
>> later today.
>> 
>> Jordan
>> 
>> 
>>> On Jan 3, 2018, at 22:56, Xiaodi Wu >> > wrote:
>>> 
>>> As has already been said, “case unknown” is source-breaking because it 
>>> conflicts with any real cases named “unknown”; “\unknown” looks like a key 
>>> path but isn’t, and I wonder if it would potentially conflict with existing 
>>> key paths.
>>> 
>>> In any case, my point was not to bikeshed the “unknown” part, but to ask 
>>> whether any consideration had been made to have the feature presented as a 
>>> flavor of default instead of a flavor of case.
>>> 
>>> On Wed, Jan 3, 2018 at 23:57 Cheyo Jimenez >> > wrote:
>>> 
>>> 
>>> On Jan 3, 2018, at 6:52 PM, Xiaodi Wu via swift-evolution 
>>> mailto:swift-evolution@swift.org>> wrote:
>>> 
 This is a very nice revision. One bikeshedding thought:
 
 Since "unknown case" is presented as a special kind of "default", can't be 
 mixed with "default", and can't be used in case patterns, why not "default 
 unknown" (or "unknown default") instead of "unknown case"?
>>> 
>>> `case _ :` is already a special case of default. 
>>> I’d rather have `case unknown :`
>>> `unknown case :` is weird because of the order of `case`. 
>>> 
>>> Another alternative is `case \unknown :`
>>> `\unknown` would also allow pattern matching. 
>>> 
>>> 
>>> 
 
 
 On Wed, Jan 3, 2018 at 8:05 PM, Jordan Rose via swift-evolution 
 mailto:swift-evolution@swift.org>> wrote:
> On Jan 2, 2018, at 18:07, Jordan Rose  > wrote:
> 
> [Proposal: 
> https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
>  
> ]
> 
> Whew! Thanks for your feedback, everyone. On the lighter side of 
> feedback—naming things—it seems that most people seem to like '@frozen', 
> and that does in fact have the connotations we want it to have. I like it 
> too.
> 
> More seriously, this discussion has convinced me that it's worth 
> including what the proposal discusses as a 'future' case. The key point 
> that swayed me is that this can produce a warning when the switch is 
> missing a case rather than an error, which both provides the necessary 
> compiler feedback to update your code and allows your dependencies to 
> continue compiling when you update to a newer SDK. I know people on both 
> sides won't be 100% satisfied with this, but does it seem like a 
> reasonable compromise?
> 
> The next questio