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

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

On non-enum values, yes I could support this. However I do not see this as a big enough issue.
On enum values? no way….

Btw this would get rid of:

        let bytesSend = send(…) // returns an Int
                
        switch bytesSend {
        case Int.min ... -1: {…}
        case 0: {…}
        case 1 ... Int.max: {…}
        default: break // <<<<<< Imposible
        }

···

On 03 Oct 2016, at 12:14, 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

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

-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 <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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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?

I absolutely cannot see why

    default: break

doesn’t already do this for you. It’s not a useless no-op, it signifies to the compiler that you really do want to ignore the other cases and it’s not a mistake.

I think there is a case for allowing default: break to be at the top of the switch but other than that, I like the fact that not having a an explicitly exhaustive switch generates an error.

···

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

--
Adrian Zubarev
Sent with Airmail

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

-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@swift.org> 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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

This is clearly not a huge issue to solve, but a pitch is a pitch.

From Swift book we know this:

Switch Statements Must Be Exhaustive

In Swift, every possible value of the control expression’s type must match the value of at least one pattern of a case. When this simply isn’t feasible (for instance, when the control expression’s type is Int), you can include a default case to satisfy the requirement.
Even for enum values an optional default would mean that you don’t care about the other cases in your current switch, which basically again would be another useless nop.

enum A {
    case a, b, c
}

var value = A.a

switch value {
     
case .a:
    value = A.b
     
default:
    () // I don't care
}

// Do something else

switch value {
     
case .b:
    value = A.c
     
default:
    () // I don't care
}
Sure the error message is there to notify you that you might forget to handle some case, but how we handle that specific case is still up to us.

I’d really like to know what could be dangerous here when default would be optional.

I can’t tell if this would have some impact on the ABI or not. I’d say it’s additive because it doesn’t break any existing code but removes an existing restriction.

The next thought might be an overkill (or maybe not):

How about making default optional everywhere + introducing a new attribute that allows the optional default on that particular enum, but by default every current existing enum should be handled exhaustively.

Bikeshedding:

enum A {
    case a, b, c
}

var value = A.a

switch value {
     
case .a:
    value = A.b
     
} // Error: switch must be exhaustive, consider adding a default clause

// VS:

@discardableCase enum B {
    case d, e, f
}

let anotherValue = B.d

switch anotherValue {
     
case .d:
    // Do something
     
case .e:
    // Do something else
         
} // Just fine; We don't care here about `.f`

···

--
Adrian Zubarev
Sent with Airmail

Am 3. Oktober 2016 um 12:28:58, Rien (rien@balancingrock.nl) schrieb:

On non-enum values, yes I could support this. However I do not see this as a big enough issue.
On enum values? no way….

Btw this would get rid of:

let bytesSend = send(…) // returns an Int

switch bytesSend {
case Int.min ... -1: {…}
case 0: {…}
case 1 ... Int.max: {…}
default: break // <<<<<< Imposible
}

On 03 Oct 2016, at 12:14, 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

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

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.)

-Joe

···

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 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>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<mailto:swift-evolution at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

There has been a little discussion on this before, and I think there's a
need for something along these lines - I've written code where I've used
'guard' to ensure that an Int was within a certain range, and then
performed a switch on the Int, requiring an ugly-looking 'default:
fatalError()' at the end to dismiss the warning.

But exhaustive switches are also useful.

There was an elegant suggestion that we apply '?' and '!' to the switch
keyword. Basically:
- 'switch <expression>' is exhaustive across values and enum states and the
compiler will warn you if you omit an enum state or default case.
- 'switch? <expression>' is not exhaustive but the compiler should still
check the flow (to ensure all paths return values, that kind of thing).
- 'switch! <expression>' is not exhaustive but it assumes one of the cases
will match, and crashes otherwise.

Basically, switch wouldn't change, but appending the '?' is equivalent to
typing 'default: break' as your final case, and appending '!' is equivalent
to typing 'default: fatalError()' as your final case. The meanings are
roughly analogous to their meanings for Optionals, so hopefully there
wouldn't be much confusion.

···

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

This is clearly not a huge issue to solve, but a pitch is a pitch.

From Swift book we know this:

*Switch Statements Must Be Exhaustive*

In Swift, every possible value of the control expression’s type must match
the value of at least one pattern of a case. When this simply isn’t
feasible (for instance, when the control expression’s type is Int), you can
include a default case to satisfy the requirement.

Even for enum values an optional default would mean that you don’t care
about the other cases in your current switch, which basically again would
be another useless nop.

enum A {
    case a, b, c
}

var value = A.a

switch value {

case .a:
    value = A.b

default:
    () // I don't care
}

// Do something else

switch value {

case .b:
    value = A.c

default:
    () // I don't care
}

Sure the error message is there to notify you that you might forget to
handle some case, but how we handle that specific case is still up to us.

I’d really like to know what could be dangerous here when default would
be optional.

I can’t tell if this would have some impact on the ABI or not. I’d say
it’s additive because it doesn’t break any existing code but removes an
existing restriction.
------------------------------

The next thought might be an overkill (or maybe not):

How about making default optional everywhere + introducing a new
attribute that allows the optional default on that particular enum, but
by default every current existing enum should be handled exhaustively.

Bikeshedding:

enum A {
    case a, b, c
}

var value = A.a

switch value {

case .a:
    value = A.b

} // Error: switch must be exhaustive, consider adding a default clause

// VS:

@discardableCase enum B {
    case d, e, f
}

let anotherValue = B.d

switch anotherValue {

case .d:
    // Do something

case .e:
    // Do something else

} // Just fine; We don't care here about `.f`

--
Adrian Zubarev
Sent with Airmail

Am 3. Oktober 2016 um 12:28:58, Rien (rien@balancingrock.nl) schrieb:

On non-enum values, yes I could support this. However I do not see this as
a big enough issue.
On enum values? no way….

Btw this would get rid of:

let bytesSend = send(…) // returns an Int

switch bytesSend {
case Int.min ... -1: {…}
case 0: {…}
case 1 ... Int.max: {…}
default: break // <<<<<< Imposible
}

> On 03 Oct 2016, at 12:14, 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
>
> _______________________________________________
> 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

I agree with previous commenters. I very much support improved exhaustiveness analysis reducing the circumstances where a default clause is necessary. But I think requiring it unless the compiler can *prove* you have covered every possibility communicates important information that facilitates reasoning to readers / maintainers of the code.

···

On Oct 3, 2016, at 12:41 PM, 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 <mailto: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 <mailto:swift-evolution@swift.org>> 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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
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

In my code, I ‘use’ the forced coverage of the case’s to be reminded of area’s where I have to update my code when the enum’s change.
I.e. choosing for an enum solution is partly motivated by the factor that case-coverage has to be complete.
I’d hate to miss that.

Rien.

···

On 03 Oct 2016, at 12:55, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

This is clearly not a huge issue to solve, but a pitch is a pitch.

From Swift book we know this:

Switch Statements Must Be Exhaustive

In Swift, every possible value of the control expression’s type must match the value of at least one pattern of a case. When this simply isn’t feasible (for instance, when the control expression’s type is Int), you can include a default case to satisfy the requirement.
Even for enum values an optional default would mean that you don’t care about the other cases in your current switch, which basically again would be another useless nop.

enum A {
    case a, b, c
}

var value = A.a

switch value {
     
case .a:
    value = A.b
     
default:
    () // I don't care
}

// Do something else

switch value {
     
case .b:
    value = A.c
     
default:
    () // I don't care
}

Sure the error message is there to notify you that you might forget to handle some case, but how we handle that specific case is still up to us.

I’d really like to know what could be dangerous here when default would be optional.

I can’t tell if this would have some impact on the ABI or not. I’d say it’s additive because it doesn’t break any existing code but removes an existing restriction.

The next thought might be an overkill (or maybe not):

How about making default optional everywhere + introducing a new attribute that allows the optional default on that particular enum, but by default every current existing enum should be handled exhaustively.

Bikeshedding:

enum A {
    case a, b, c
}

var value = A.a

switch value {
     
case .a:
    value = A.b
     
} // Error: switch must be exhaustive, consider adding a default clause

// VS:

@discardableCase enum B {
    case d, e, f
}

let anotherValue = B.d

switch anotherValue {
     
case .d:
    // Do something
     
case .e:
    // Do something else
         
} // Just fine; We don't care here about `.f`

--
Adrian Zubarev
Sent with Airmail

Am 3. Oktober 2016 um 12:28:58, Rien (rien@balancingrock.nl) schrieb:

On non-enum values, yes I could support this. However I do not see this as a big enough issue.
On enum values? no way….

Btw this would get rid of:

let bytesSend = send(…) // returns an Int

switch bytesSend {
case Int.min ... -1: {…}
case 0: {…}
case 1 ... Int.max: {…}
default: break // <<<<<< Imposible
}

> On 03 Oct 2016, at 12:14, 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
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

I’m not sure about the design itself, but the idea is great. I couldn’t even foresee that there might be a need for switch!. This is definitely better than my suggestion of a new attribute. I most cases I’d need switch? to replace the ugly-looking if case … { … } else if case … { … }.

Was there a rejected proposal on this that I missed?

···

--
Adrian Zubarev
Sent with Airmail

Am 3. Oktober 2016 um 13:16:54, Ross O'Brien (narrativium+swift@gmail.com) schrieb:

There has been a little discussion on this before, and I think there's a need for something along these lines - I've written code where I've used 'guard' to ensure that an Int was within a certain range, and then performed a switch on the Int, requiring an ugly-looking 'default: fatalError()' at the end to dismiss the warning.

But exhaustive switches are also useful.

There was an elegant suggestion that we apply '?' and '!' to the switch keyword. Basically:
- 'switch <expression>' is exhaustive across values and enum states and the compiler will warn you if you omit an enum state or default case.
- 'switch? <expression>' is not exhaustive but the compiler should still check the flow (to ensure all paths return values, that kind of thing).
- 'switch! <expression>' is not exhaustive but it assumes one of the cases will match, and crashes otherwise.

Basically, switch wouldn't change, but appending the '?' is equivalent to typing 'default: break' as your final case, and appending '!' is equivalent to typing 'default: fatalError()' as your final case. The meanings are roughly analogous to their meanings for Optionals, so hopefully there wouldn't be much confusion.

On Mon, Oct 3, 2016 at 11:55 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:
This is clearly not a huge issue to solve, but a pitch is a pitch.

From Swift book we know this:

Switch Statements Must Be Exhaustive

In Swift, every possible value of the control expression’s type must match the value of at least one pattern of a case. When this simply isn’t feasible (for instance, when the control expression’s type is Int), you can include a default case to satisfy the requirement.
Even for enum values an optional default would mean that you don’t care about the other cases in your current switch, which basically again would be another useless nop.

enum A {
    case a, b, c
}

var value = A.a

switch value {
      
case .a:
    value = A.b
      
default:
    () // I don't care
}

// Do something else

switch value {
      
case .b:
    value = A.c
      
default:
    () // I don't care
}
Sure the error message is there to notify you that you might forget to handle some case, but how we handle that specific case is still up to us.

I’d really like to know what could be dangerous here when default would be optional.

I can’t tell if this would have some impact on the ABI or not. I’d say it’s additive because it doesn’t break any existing code but removes an existing restriction.

The next thought might be an overkill (or maybe not):

How about making default optional everywhere + introducing a new attribute that allows the optional default on that particular enum, but by default every current existing enum should be handled exhaustively.

Bikeshedding:

enum A {
    case a, b, c
}

var value = A.a

switch value {
      
case .a:
    value = A.b
      
} // Error: switch must be exhaustive, consider adding a default clause

// VS:

@discardableCase enum B {
    case d, e, f
}

let anotherValue = B.d

switch anotherValue {
      
case .d:
    // Do something
      
case .e:
    // Do something else
          
} // Just fine; We don't care here about `.f`

--
Adrian Zubarev
Sent with Airmail

Am 3. Oktober 2016 um 12:28:58, Rien (rien@balancingrock.nl) schrieb:

On non-enum values, yes I could support this. However I do not see this as a big enough issue.
On enum values? no way….

Btw this would get rid of:

let bytesSend = send(…) // returns an Int

switch bytesSend {
case Int.min ... -1: {…}
case 0: {…}
case 1 ... Int.max: {…}
default: break // <<<<<< Imposible
}

On 03 Oct 2016, at 12:14, 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

_______________________________________________
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

There has been a little discussion on this before, and I think there's a need for something along these lines - I've written code where I've used 'guard' to ensure that an Int was within a certain range, and then performed a switch on the Int, requiring an ugly-looking 'default: fatalError()' at the end to dismiss the warning.

But exhaustive switches are also useful.

There was an elegant suggestion that we apply '?' and '!' to the switch keyword. Basically:
- 'switch <expression>' is exhaustive across values and enum states and the compiler will warn you if you omit an enum state or default case.
- 'switch? <expression>' is not exhaustive but the compiler should still check the flow (to ensure all paths return values, that kind of thing).

Swift: The questionable language… lol

- 'switch! <expression>' is not exhaustive but it assumes one of the cases will match, and crashes otherwise.

Basically, switch wouldn't change, but appending the '?' is equivalent to typing 'default: break' as your final case, and appending '!' is equivalent to typing 'default: fatalError()' as your final case. The meanings are roughly analogous to their meanings for Optionals, so hopefully there wouldn't be much confusion.

Though I am not 100% on the “feel” of this, it would work imo.

Rien.

···

On 03 Oct 2016, at 13:16, Ross O'Brien <narrativium+swift@gmail.com> wrote:

On Mon, Oct 3, 2016 at 11:55 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:
This is clearly not a huge issue to solve, but a pitch is a pitch.

From Swift book we know this:

Switch Statements Must Be Exhaustive

In Swift, every possible value of the control expression’s type must match the value of at least one pattern of a case. When this simply isn’t feasible (for instance, when the control expression’s type is Int), you can include a default case to satisfy the requirement.

Even for enum values an optional default would mean that you don’t care about the other cases in your current switch, which basically again would be another useless nop.

enum A {
    case a, b, c
}

var value = A.a

switch value {
     
case .a:
    value = A.b
     
default:
    () // I don't care
}

// Do something else

switch value {
     
case .b:
    value = A.c
     
default:
    () // I don't care
}

Sure the error message is there to notify you that you might forget to handle some case, but how we handle that specific case is still up to us.

I’d really like to know what could be dangerous here when default would be optional.

I can’t tell if this would have some impact on the ABI or not. I’d say it’s additive because it doesn’t break any existing code but removes an existing restriction.

The next thought might be an overkill (or maybe not):

How about making default optional everywhere + introducing a new attribute that allows the optional default on that particular enum, but by default every current existing enum should be handled exhaustively.

Bikeshedding:

enum A {
    case a, b, c
}

var value = A.a

switch value {
     
case .a:
    value = A.b
     
} // Error: switch must be exhaustive, consider adding a default clause

// VS:

@discardableCase enum B {
    case d, e, f
}

let anotherValue = B.d

switch anotherValue {
     
case .d:
    // Do something
     
case .e:
    // Do something else
         
} // Just fine; We don't care here about `.f`

--
Adrian Zubarev
Sent with Airmail

Am 3. Oktober 2016 um 12:28:58, Rien (rien@balancingrock.nl) schrieb:

On non-enum values, yes I could support this. However I do not see this as a big enough issue.
On enum values? no way….

Btw this would get rid of:

let bytesSend = send(…) // returns an Int

switch bytesSend {
case Int.min ... -1: {…}
case 0: {…}
case 1 ... Int.max: {…}
default: break // <<<<<< Imposible
}

> On 03 Oct 2016, at 12:14, 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
>
> _______________________________________________
> 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

-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 <mailto: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 <mailto:swift-evolution@swift.org>> 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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
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

This seems to me like the perfect answer for Swift.

···

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.)

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> 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>wrote:
> >
> > I know that there is this note in Commonly Rejected Changes<
https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md
>:
> >
> > 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<mailto:swift-evolution at swift.org>
> > 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
https://lists.swift.org/mailman/listinfo/swift-evolution

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 <mailto: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 <mailto: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 <mailto: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 <mailto:swift-evolution@swift.org>> 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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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 <mailto: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 <mailto: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 <mailto:swift-evolution@swift.org>> 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

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 <mailto: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 <mailto: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 <mailto: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 <mailto: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 <mailto:swift-evolution@swift.org>> 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