[Pitch] Can we make `default` on switches optional?

The best answer is always "that would be an ecumenical matter...". It works here too ;).

···

Sent from my iPhone

On 4 Oct 2016, at 03:44, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 3, 2016, at 8:03 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 3, 2016, at 9:39 AM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

-1 in general. I want smarter exhaustiveness analysis, but I don’t want to be able to ignore cases that “can’t happen” (so say we, writer of bugs) when they’re clearly in the domain of possible values that can be fed to a switch-case. Exhaustiveness guarantees wellformedness of a program that does happen to go wrong, and makes it much easier to verify the correctness of the flow of control of the containing block because all points from the switch must be covered. We also don’t have the type-level tools to convince the checker to allow you to remove unreachable cases. If it’s really a problem that you are writing default cases everywhere, just bailout in a fatal error with a nice description. It never hurts.

I can see the utility of a `switch!` construct that introduces the 'default: fatalError()' on your behalf. No matter how much analysis we do, there are always going to be cases with 'where' guards and expr patterns that we can't decidably analyze for exhaustiveness, for which runtime safety is the best we can offer. (That said, it'd fall squarely in the "sugar" bucket, so while it's an interesting idea to explore, it's not immediate Swift 4 Phase 1 material.)

This seems to me like the perfect answer for Swift.

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

I think I agree with you. The postfix `!` operator is always shorthand for `fatalError()` (and some more syntax), and it would fit nicely with `default: fatalError()`.

The Swift usage of `?` is indeed different than `default: break` would do, so `switch?` wouldn’t convey the right message. I hadn’t given it enough thought. I still think a shorthand for `default: break` would be _nice_, but it surely shouldn’t change the `?` consistency, it also shouldn’t replace the current `switch` (as exhaustiveness is very useful) and it’s probably not worth introducing new syntax for.

···

On 4 Oct 2016, at 16:36, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

There is a plausible argument for `switch!`, because it is not possible for the compiler to prove exhaustiveness in all circumstances where you might know it to be the case.

However, I'd be very against `switch?`: it undermines the exhaustiveness guarantee of the switch statement and is wholly inconsistent with Swift usage of `?`, which indicates the possibility of an Optional. We simply don't need a new spelling for `default: break`.
On Tue, Oct 4, 2016 at 3:35 AM Tim Vermeulen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I agree about exhaustiveness checks being very useful. There was a suggestion for `switch?` implicitly adding `default: break`, `switch!` implicitly adding `default: fatalError()`, and `switch` remaining as it is now. I think that’s a great compromise, would you be in favor of that?

> -1. The “default: break” is not only not difficult to write, it clearly communicates the programmer’s intent to only handle a subset of the cases. Without it, it is impossible to know whether that was intended, or by accident. Furthermore, the exhaustiveness by default can catch many mistakes, including after an additional case is added to an enum.
>
> Charles
>
> > On Oct 3, 2016, at 5:14 AM, Adrian Zubarev via swift-evolution<swift-evolution at swift.org <http://swift.org/&gt;&gt;wrote:
> >
> > I know that there is this note in Commonly Rejected Changes<https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md&gt;:
> >
> > Remove support for default: in switch and just use case _:: default is widely used, case _ is too magical, and default is widely precedented in many C family languages.
> > I really like to use the switch instead of if case for pattern matching, just because it’s neat block design. I do not want to remove default from switches because it’s a must have and powerful feature.
> >
> > I’d like to know why switches must be exhaustive.
> >
> > switch someValue {
> >
> > case …:
> > // Do something
> >
> > case …:
> > // Do something else
> >
> > default:
> > () // useless nop; do nothing when no pattern matched
> > }
> >
> > // VS:
> >
> > if case … {
> >
> > } else if case … {
> >
> > } else if case … {
> >
> > } // No need for `else`
> > Can’t we make default optional, or at least on non-enum values?
> >
> >
> >
> >
> > --
> > Adrian Zubarev
> > Sent with Airmail
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org <http://swift.org/&gt;&lt;mailto:swift\-evolution <mailto:swift-evolution> at swift.org <http://swift.org/&gt;&gt;
> > https://lists.swift.org/mailman/listinfo/swift-evolution&lt;https://lists.swift.org/mailman/listinfo/swift-evolution&gt;
>
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

If you're as concerned about code size as stdlib is then I'd be interested to know what you're writing! These are paths to terminate your application which is necessarily going to be orders of magnitude larger than stdlib is and so can "eat the cost" of a few more global db's, some loads, and a call or three.

~Robert Widmann

2016/10/03 15:14、Ben Rimmington <me@benrimmington.com> のメッセージ:

···

Yes, but <https://github.com/apple/swift/pull/2379&gt; uses `Builtin.unreachable()` because it:

"Saves a bit of code size in the standard library by eliminating some
static strings and function calls."

Clang has both `__builtin_unreachable()` and `llvm_unreachable()`:

<Clang Language Extensions — Clang 18.0.0git documentation;

<LLVM Coding Standards — LLVM 18.0.0git documentation;

-- Ben

On 3 Oct 2016, at 20:01, Robert Widmann <devteam.codafi@gmail.com> wrote:

fatalError has defaults for its arguments so it can be used as a nullary unreachable function already.

~Robert Widmann

On Oct 3, 2016, at 2:50 PM, Ben Rimmington via swift-evolution <swift-evolution@swift.org> wrote:

Instead of using `fatalError(_:file:line:)` in `default` cases, would a public `unreachable()` function be more efficient?

e.g. <https://github.com/apple/swift/pull/2379&gt;

-- Ben

On 3 Oct 2016, at 18:50, João Pinheiro via swift-evolution <swift-evolution@swift.org> wrote:

-1 from me too.

Avoiding having to write "default: break" isn't a good justification to introduce new syntax. It would make the understanding of case switches harder without providing any real benefit for the syntax bloat.

João Pinheiro

On 03 Oct 2016, at 19:41, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

-1 from me as well. This suggestion falls into the same category as those about making `else` optional after `guard`, which is repeatedly rejected. Since code is read more often than written, explicit handling of the default case never hurts and can increase clarity. Not having to write `default: break` offers no help in writing correct code and IMO can't justify new syntax or the changing of a well-known control statement.

On Mon, Oct 3, 2016 at 11:39 AM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

-1 in general. I want smarter exhaustiveness analysis, but I don’t want to be able to ignore cases that “can’t happen” (so say we, writer of bugs) when they’re clearly in the domain of possible values that can be fed to a switch-case. Exhaustiveness guarantees wellformedness of a program that does happen to go wrong, and makes it much easier to verify the correctness of the flow of control of the containing block because all points from the switch must be covered. We also don’t have the type-level tools to convince the checker to allow you to remove unreachable cases. If it’s really a problem that you are writing default cases everywhere, just bailout in a fatal error with a nice description. It never hurts.

~Robert Widmann

On Oct 3, 2016, at 6:14 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

I know that there is this note in Commonly Rejected Changes:

Remove support for default: in switch and just use case _:: default is widely used, case _ is too magical, and default is widely precedented in many C family languages.
I really like to use the switch instead of if case for pattern matching, just because it’s neat block design. I do not want to remove default from switches because it’s a must have and powerful feature.

I’d like to know why switches must be exhaustive.

switch someValue {
     
case …:
    // Do something
     
case …:
    // Do something else

default:
    () // useless nop; do nothing when no pattern matched
}

// VS:

if case … {
     
} else if case … {
     
} else if case … {
     
} // No need for `else`
Can’t we make default optional, or at least on non-enum values?

--
Adrian Zubarev
Sent with Airmail

I agree with Tim; I'm a +1 for switch! for a convenient means of erroring out, but I think switch? is a bit too different from normal usage of the question-mark.

One other alternative might be if there could be some kind of switch else syntax, kind of like a guard statement, allowing options on what to do? Only problem is how best to structure it, as the use of break might confusing as to its scope, like so:

  switch(foo) else break { // Break from the switch, or the enclosing block?

So I'm not 100% on that. But it would mean that switch! would be a shorthand for switch else fatalError().

···

On 4 Oct 2016, at 16:30, Tim Vermeulen via swift-evolution <swift-evolution@swift.org> wrote:

I think I agree with you. The postfix `!` operator is always shorthand for `fatalError()` (and some more syntax), and it would fit nicely with `default: fatalError()`.

The Swift usage of `?` is indeed different than `default: break` would do, so `switch?` wouldn’t convey the right message. I hadn’t given it enough thought. I still think a shorthand for `default: break` would be _nice_, but it surely shouldn’t change the `?` consistency, it also shouldn’t replace the current `switch` (as exhaustiveness is very useful) and it’s probably not worth introducing new syntax for.

On 4 Oct 2016, at 16:36, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

There is a plausible argument for `switch!`, because it is not possible for the compiler to prove exhaustiveness in all circumstances where you might know it to be the case.

However, I'd be very against `switch?`: it undermines the exhaustiveness guarantee of the switch statement and is wholly inconsistent with Swift usage of `?`, which indicates the possibility of an Optional. We simply don't need a new spelling for `default: break`.

I will courteously jump in with a -1 for both switch! and switch?. I get how pretty they are at first glance: they have symmetry with existing constructs. However:

* I doubt they'll be used much and I don't think something should be added to the language without measurable and consequential benefits.

* I don't think

    `default: fatalError() // this should never happen, cases are exhaustive`

is a burden to type, in fact, I like how self-documenting it is, even if the compiler sometimes guesses wrong -- in fact, I think the compiler *should* guess wrong, especially on especially oddball case sets like `(.min ..< 0)` and `(0 ... .max)`, let alone cases where you only want the even values within those ranges.

* I do think that visually scanning for switch variants places a burden on code readability. Unlike try? and try!, the switch!? statement will likely be lines and lines away from where it impacts code. The place that best means "this should never happen, cases are exhaustive" is the default case.

-- E

···

On Oct 5, 2016, at 8:29 AM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 4 Oct 2016, at 16:30, Tim Vermeulen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I think I agree with you. The postfix `!` operator is always shorthand for `fatalError()` (and some more syntax), and it would fit nicely with `default: fatalError()`.

The Swift usage of `?` is indeed different than `default: break` would do, so `switch?` wouldn’t convey the right message. I hadn’t given it enough thought. I still think a shorthand for `default: break` would be _nice_, but it surely shouldn’t change the `?` consistency, it also shouldn’t replace the current `switch` (as exhaustiveness is very useful) and it’s probably not worth introducing new syntax for.

On 4 Oct 2016, at 16:36, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

There is a plausible argument for `switch!`, because it is not possible for the compiler to prove exhaustiveness in all circumstances where you might know it to be the case.

However, I'd be very against `switch?`: it undermines the exhaustiveness guarantee of the switch statement and is wholly inconsistent with Swift usage of `?`, which indicates the possibility of an Optional. We simply don't need a new spelling for `default: break`.

I agree with Tim; I'm a +1 for switch! for a convenient means of erroring out, but I think switch? is a bit too different from normal usage of the question-mark.

One other alternative might be if there could be some kind of switch else syntax, kind of like a guard statement, allowing options on what to do? Only problem is how best to structure it, as the use of break might confusing as to its scope, like so:

  switch(foo) else break { // Break from the switch, or the enclosing block?

So I'm not 100% on that. But it would mean that switch! would be a shorthand for switch else fatalError().

We already have that in default, The syntax is different, but at least the meaning of break is unambiguous.

···

On 5 Oct 2016, at 15:29, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

I agree with Tim; I'm a +1 for switch! for a convenient means of erroring out, but I think switch? is a bit too different from normal usage of the question-mark.

One other alternative might be if there could be some kind of switch else syntax, kind of like a guard statement, allowing options on what to do? Only problem is how best to structure it, as the use of break might confusing as to its scope, like so:

  switch(foo) else break { // Break from the switch, or the enclosing block?