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

Adrian Zubarev adrian.zubarev at devandartist.com
Mon Oct 3 06:30:02 CDT 2016


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


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


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161003/8e52282f/attachment.html>


More information about the swift-evolution mailing list