20

Swift 2's guide mentions that you can end program execution of an if statement. I personally have never used break with if-statement.

A break statement ends program execution of a loop, an if statement, or a switch statement...When a break statement is followed by the name of a statement label, it ends program execution of the loop, if statement, or switch statement named by that label.

In what situation would one be using break in an if-statement? This language feature seems useless.

TEST:
if (true) {
    break TEST
}
rholmes
  • 4,064
  • 3
  • 25
  • 34
Boon
  • 40,656
  • 60
  • 209
  • 315
  • 1
    The only case I can think of you would do that in is using break inside an if statement inside a loop... But you do that in all other languages. – Andy Ibanez Jul 18 '15 at 02:27
  • In that case, it's still breaking out of a loop, not an if-statement. I fail to see the value of the ability to break out of an if-statement. – Boon Jul 18 '15 at 02:50
  • 1
    @Boon I can't think of one either. Every possible use I can rewrite more elegantly. – Aaron Brager Jul 18 '15 at 02:53

3 Answers3

21

For example if you want to describe a number (with Strings) with reference to sets of numbers (even/rational/negative numbers) your code could look something like this:

if condition1 {
    // code
    if condition2 {
        // code
        if condition3 {
            // code
            if condition4 {
                //code
            }
        }
    }
}

You can achieve the same logic but without the nested ifs by refactoring it (using guard):

OuterIf: if condition1 {
    // code

    guard condition2 else { break OuterIf }
    // code

    guard condition3 else { break OuterIf }
    // code

    guard condition4 else { break OuterIf }
    // code
}

// reads even better when breaking out of "do"
scope: do {
    guard condition1 else { break scope }
    // code

    guard condition2 else { break scope }
    // code

    guard condition3 else { break scope }
    // code

    guard condition4 else { break scope }
    // code

}

You might think that this can also be achieved with switch and fallthrough but this doesn't work with "normal" cases because it checks all conditions and if one condition is met all following conditions aren't even evaluated.

So the fallthough has to be called conditionally.

This does work but I isn't very readable not to mention its "beauty":

let x = 4
switch x {
case _ where condition1:
    // code
    if condition2 { fallthrough }
case _ where false:
    // code
    if condition3 { fallthrough }
case _ where false:
    // code
    if condition4 { fallthrough }
case _ where false:
    // code
    break
default: break
}
Qbyte
  • 12,753
  • 4
  • 41
  • 57
  • Nice example - upvoted, though the break is applied towards guard, not if. Can you think of a case where you would want to break out of an if-statement? – Boon Jul 18 '15 at 12:56
  • In my playground the break exits the scope of the `if` statement. You can solve all problems without breaking out of the `if` statement but it reads much nicer. In addition breaking out of `do` is even better in term of readability (added Example above). – Qbyte Jul 18 '15 at 13:59
  • I've learned a new thing today, regarding "guard" and escaping only from a specified scope. Cool! – Starsky Apr 11 '19 at 12:58
  • After four years of Swift programming, I never knew there was a `do` statement (without `try`s)! – Jay Lee Jan 18 '22 at 04:45
11

Using break with an if statement seems a bit contrived, and I can't think of a place where style would demand it. It does, however, save an extra level of indentation when skipping the latter portion of an if statement in an if-else clause, which can be useful for deeply nested loops.

In other languages, a popular (and/or controversial) idiom is to use labels for handling errors in deeply nested functions. For example, one might want to break out of a loop on error, like this:

func testBreak3() {
    // doesn't compile!!!
    let a = false, b = true, x = 10, y = 20, err = true
    if !a {
        if b && x > 0 {
            if y < 100 {
                if err {
                    break handleError
                }
                // some statements
            } else {
                // other stuff
            }

        }
    }
    return  // avoid error handling

    handleError:
    print("error")
    // handle the error
}

But in Swift (I'm using 2.0 as a reference), labels are different than with other languages; the above example doesn't compile for two reasons: The label isn't declared yet when it's used, and the label must be directly associated with a do, while, if, or case statement. Furthermore, break within an if or do statements requires that statement to be labeled. We can fix this as follows, although the changes make the solution less attractive due to additional tracking via the errorFlagged variable, making refactoring more attractive:

func testBreak() {
    let a = false, b = true, x = 10, y = 20, err = true
    var errorFlagged = false
    nestedIf: if !a {
        if b && x > 0 {
            if y < 100 {
                if err {
                    errorFlagged = true
                    break nestedIf
                }
                // some statements
            } else {
                // other stuff
            }
        }
    }

    // skip handling if no error flagged.
    if errorFlagged {
        print("error")
        // handle error
    }
}
rholmes
  • 4,064
  • 3
  • 25
  • 34
  • I'm curious why refactoring is more attractive here, and how you might refactor. This solution seems like the cleanest way for me to break out of a check for the presence of a certain deprecated launch option on the basis of an SDK version check. Does that strike you as a situation where style demands this solution? – eLillie Dec 15 '16 at 22:55
  • 1
    @eLillie The solution above does seem fairly well suited to your situation, with what little I know. Code with lower level of nesting is easier to read, all things considered. Refactoring might be something to reduce the nesting, such as a function to perform all the checks. Subject, of course, to all the other concerns like number of parameters to the function, etc. – rholmes Dec 16 '16 at 16:09
-1

I know this is old topic, but just now I used break and it was needed. So my example I have array of objects. When user taps on a cell, i.parameter becomes True for the object in that cell. I need to know when all the objects in the array have i.parameter = True , that's the condition to stop the game.

func forTimer(){
   for i in array {
    if i.parameter == false {
     break
  }
 }
}
timer = Timer.scheduledTimer(timeInterval: 0.001, target: self, selector: #selector(forTimer), userInfo: nil, repeats: true)

Even if one i.parameter = false, I do not need to check the rest of the array. This function is called every millisecond, so I will not have to check the whole array every millisecond.

Nalov
  • 578
  • 5
  • 9
  • The OP is asking for the use case of using `break`s on if statements, not for loops. – Jay Lee Nov 20 '19 at 06:52
  • The 'break' is used in if nested loop not in for loop. I had not put the braces because i thought it is understandable. I have edited and added the braces. – Nalov Nov 20 '19 at 14:56
  • Your break statement breaks the outer for, not the if statement inside. The OP asked about breaking an if statement. – Jay Lee Nov 21 '19 at 01:38
  • The op asked "In what situation would one be using break in an if-statement? ", i have answered that. Please read the question. I do not think my answer from a year ago deserves minus. – Nalov Nov 21 '19 at 07:13