Noop for Swift's Exhaustive Switch Statements - swift

Swift requires exhaustive switch statements, and that each case have executable code.
'case' label in a 'switch' should have at least one executable statement
Has anybody settled on a good way to handle the cases where you don't want to actually do anything? I can put a println() in there, but that feels dirty.

According to the book, you need to use break there:
The scope of each case can’t be empty. As a result, you must include at least one statement following the colon (:) of each case label. Use a single break statement if you don’t intend to execute any code in the body of a matched case.

You can use a break statement:
let vegetable = "red pepper"
var vegetableComment: String = "Nothing"
switch vegetable {
case "cucumber", "watercress":
break // does nothing
case let x where x.hasSuffix("pepper"):
vegetableComment = "Is it a spicy \(x)?"
default:
vegetableComment = "Everything tastes good in soup."
}
Example modified from the docs

Below is one option for null statement, but maybe not a good solution. I cannot find a statement like python pass
{}()
for switch case, break is better choice.
break

Do nothing in exhaustive switch case statements:
Swift:
switch yourVariable {
case .someCase:
break
}
SwiftUI:
switch yourVariable {
case .someCase:
EmptyView() // break does not work with ViewBuilder
}
Using EmptyView() instead of break in SwiftUI views prevents the error:
Closure containing control flow statement cannot be used with function
builder ViewBuilder.
EmptyView() is a SwiftUI standard view (tested with Xcode 12, iOS 14) and does not need to be defined yourself.

In addition to break mentioned in other answers, I have also seen () used as a no-op statement:
switch 0 == 1 {
case true:
break
case false:
()
}
Use () if you find break confusing or want to save 3 characters.

The cleanest solution I've found is to simply include your last statement in the switch case as your default. This avoids the need to add break or other unnecessary statements while still covering all possible cases.
For example:
switch myVar {
case 0:
myOtherVar = "Red"
case 1:
myOtherVar = "Blue"
default:
myOtherVar = "Green"
}

You can check specific case, no need to be exhustive with switch cases
Say you have a enum like this,
enum Selection {
case one
case two
case three
}
var myCase = Selection.one
you can check like this,
if case .one = myCase {
print("one")
}

A clean solution I use for my default case is:
default: ()

Related

Using #unknown default in swift 5 enum : How to suppress "Default will never be executed" warning?

Let's say I have an existing code as follows:
enum SomeEnumCases {
case existing
case alreadyExisting
}
func doSomething(withEnums enumCase: SomeEnumCases) {
switch enumCase {
case .existing:
print("This case was already existing")
case .alreadyExisting:
print("This case was already existing too...")
}
}
Now, if I were to add a new case the the enum, the function above would show a compile error saying the switch case must be exhaustive, and I would be FORCED to handle the new missing case. I would add a third case in the switch statement, or add a default statement.
Now, I order to handle such unforeseen enum cases, I would like to add an #unknown default case to the existing function above. The only problem is, now it would give me a warning saying Default will never be executed.
So the question is, how do I future-proof my enum such that I can:
Exhaustively handle all current enum cases, AND
Have a default handling mechanism for the future unknown case, AND
See a warning only when newer cases are added and these cases must be handled by the default case.
That means, the following code SHOULD NOT give warnings:
enum SomeEnumCases {
case existing
case alreadyExisting
}
func doSomething(withEnums enumCase: SomeEnumCases) {
switch enumCase {
case .existing:
print("This case was already existing")
case .alreadyExisting:
print("This case was already existing too...")
#unknown default: // <-- warning: Default will never be executed: should be suppressed
print("Alright, this is something new and exciting !!")
}
}
but the following code SHOULD give a warning:
enum SomeEnumCases {
case existing
case alreadyExisting
case new
}
func doSomething(withEnums enumCase: SomeEnumCases) {
switch enumCase { // <-- warning: Switch must be exhaustive: This should stay.
case .existing:
print("This case was already existing")
case .alreadyExisting:
print("This case was already existing too...")
#unknown default:
print("Alright, this is something new and exciting !!")
}
}
Is that possible through #unknown or otherwise ?
The warning is probably somewhat misleading as the spec says (emphasis added):
A nonfrozen enumeration is a special kind of enumeration that may gain new enumeration cases in the future—even after you compile and ship an app. Switching over a nonfrozen enumeration requires extra consideration. When a library’s authors mark an enumeration as nonfrozen, they reserve the right to add new enumeration cases, and any code that interacts with that enumeration must be able to handle those future cases without being recompiled. Only the standard library, Swift overlays for Apple frameworks, and C and Objective-C code can declare nonfrozen enumerations. Enumerations you declare in Swift can’t be nonfrozen.
So it's not so much that the branch will never be executed but that the feature is completely unsupported for your SomeEnumCases user-defined Swift enum.
There seems to be no supported way of doing what you wish in Swift 5, and some indications that adding cases is seen as a breaking change as it could/would break binary compatibility, but Swift is an ever moving target...

Empty cases in Swift

What is the difference between line A and line B:
let a = 1
switch a {
case 1:
break;//line A
case 2:
print("2")
default:
()//line B
}
My guess is that break is saying leave the switch, whereas () is saying do nothing.
I'm not sure what to search for this, and I'm new to Swift, so links are appreciated
In your example, there is no difference. They are both placeholders. The rule is that a case cannot be completely empty. Both are acting as ways of meeting that requirement.

Using enum and switch case combination in Swift [duplicate]

This question already has answers here:
Switch in Swift - Case label in a switch should have at least one executable statement
(2 answers)
Noop for Swift's Exhaustive Switch Statements
(8 answers)
Closed 7 years ago.
Here is my code:
enum GameScreen
{
case kSceneFlashScreen
case kSceneMainMenu
case kSceneGameScreen
case kSceneStoreScreen
case kSceneGameOver
}
class YSGameManager: NSObject {
func replaceGameScene(inScreen: GameScreen)
{
switch inScreen
{
case GameScreen.kSceneGameScreen: //Error for here
case GameScreen.kSceneMainMenu : //here also error
}
}
}
Eror LOG: 'case' label in a 'switch' should have at least one executable statement
How to use enum in switch case in Swift ?
There's an error because you haven't got anything after : and before the next case. To solve this you can:
1. Add some code to do something.
2. Add fallthrough if you want to move to the next case. This may have been what you were trying to do. However, in Swift, switch statements don't fallthrough by default to the next case, they break.
3. Add break to stop the switch statement.
It’s complaining that you need to actually do something after the matching case. Otherwise there’s not much point matching it, and chances are it’s a typo.
Other possibly than coverage i.e. if you don’t want a default, you want to name every possible enum, even though you don’t want to do anything for some of them. In which case, stick in a break:
switch inScreen {
case kSceneGameScreen:
break
// etc.
}
Note, there’s no implicit fall through in Swift’s switch statements. You need to give one explicitly:
switch inScreen {
case kSceneGameScreen:
// do a game-screen-specific thing
fallthrough // then
case kSceneMainMenu:
// do a thing for both
// kSceneGameScreen and kSceneMainMenu
// etc.
}
But if you just want to match two possibilities, you don’t need to use fall through, you can just combine them with ,:
switch inScreen {
case kSceneGameScreen, kSceneMainMenu:
// do a thing for both
// kSceneGameScreen and kSceneMainMenu
// etc.
}

Pass Keyword in Swift

I know that the keyword "pass" in Python will allow one to leave a line of code empty where it should have contained an executable statement. Is there a similar keyword in Swift?
I am using a switch statement and Swift requires there to be a default case. The code should reach the default statement most of the time and I want nothing to be done in this case.
You can break out of the default case. Swift just wants you to be explicit about that to avoid bugs.
Here's a simple example:
enum Food {
case Banana
case Apple
case ChocolateBar
}
func warnIfUnhealthy(food : Food) {
switch food {
case .ChocolateBar:
println("Don't eat it!")
default:
break
}
}
let candy = Food.ChocolateBar
warnIfUnhealthy(candy)
The proper way to add a catch-all without an action to a switch statement is to add
default: break
at the end.

Combine default case with other cases

Given the following enum in C# and a switch/case to return the a border color of a textbox according its state for example.
enum TextboxState {
Default,
Error
}
switch(foo) {
default:
case TextboxState.Default: return Color.Black;
case TextboxState.Error: return Color.Red;
}
So basically I define a real and not just by convention default state aka TextboxState.Default by adding the default: case. I just want to do this to prevent future breaking changes if new values are added to the enum.
According to the Swift book this is not possible:
“If it is not appropriate to provide a switch case for every possible
value, you can define a default catch-all case to cover any values
that are not addressed explicitly. This catch-all case is indicated by
the keyword default, and must always appear last.”
The paragraph is quite clear about that, so I assume my pattern above does not apply to Swift or do I miss something? Is there another way to archive something like the above code?
You can use fallthrough to do that, by moving the shared behavior in the default case, and using fallthrough in all cases for which you want the shared behavior to occur.
For example, if this is your enum (added a 3rd case to show it can handle multiple fall throughs):
enum TextboxState {
case Default
case Error
case SomethingElse
}
you can format the switch statement as follows:
switch(foo) {
case TextboxState.Error:
return UIColor.redColor()
case TextboxState.Default:
fallthrough
case TextboxState.SomethingElse:
fallthrough
default:
return UIColor.blackColor()
}
Each fallthrough moves the execution point to the next case, up to the default case.
Delete the default: line from your switch. Even if you someday add additional cases to your enum, the Swift compiler will complain if you don't add corresponding cases to every switch that uses the enum. And FYI, you don't need to specify the TextboxState. before the case values in the switch, because the compiler knows that foo is a TextboxState. The resulting code would be:
switch(foo) {
case .Default: return Color.Black;
case .Error: return Color.Red;
}
although, for consistency, I'd put the .Error case before the .Default one.