Using 'If-Case' Format in Boolean Assignment in Swift

How case works in if-case

The operator is if case, so you can't put parentheses. The syntax and behavior are based on those of the case statement in a Swift switch statement (see my online book if you need details). In a case statement, 20...30 is an interval, used as a pattern, which operates by using contains against the interval. The equals sign is indeed truly confusing, but that was their first attempt at a syntax for expressing what the case statement should be comparing with (i.e. the tag that comes after the switch keyword in a switch statement).

So, if you understand this:

switch age {
case 20...30:
// do stuff
default:break
}

... then you understand how it is morphed directly into this:

if case 20...30 = age {
// do stuff
}

if (variable assignment) syntax query (Swift)

The let a = b syntax used in an if statement is called optional binding. You can read more about it here. Essentially, if b is nil, the condition is treated as "false". If b is not nil, the condition is treated as "true", and a non optional constant a will now have the value that b has, and you can use it inside the if block.

Swift if statements also allow you to specify multiple conditions. All of them has to be "true" for the if block to be executed. These conditions doesn't have to be boolean expressions. They could be any of the following:

  • Boolean expressions
  • Optional Binding
  • #available check
  • case pattern matching

If you have two boolean expressions and you want to run some code if both of them are true, you could use && to join them together, but if you have 2 optionals that you want to bind, or one boolean expression and one optional binding, or any combination of the above, you'd need to use a comma to separate the conditions.

Using the Swift if let with logical AND operator &&

As of Swift 1.2, this is now possible. The Swift 1.2 and Xcode 6.3 beta release notes state:

More powerful optional unwrapping with if let — The if let construct
can now unwrap multiple optionals at once, as well as include
intervening boolean conditions. This lets you express conditional
control flow without unnecessary nesting.

With the statement above, the syntax would then be:

if let tabBarController = window!.rootViewController as? UITabBarController where tabBarController.viewControllers.count > 0 {
println("do stuff")
}

This uses the where clause.

Another example, this time casting AnyObject to Int, unwrapping the optional, and checking that the unwrapped optional meets the condition:

if let w = width as? Int where w < 500
{
println("success!")
}

For those now using Swift 3, "where" has been replaced by a comma. The equivalent would therefore be:

if let w = width as? Int, w < 500
{
println("success!")
}

Swift if statement - multiple conditions separated by commas?

Yes when you write

if let a = optA, let b = optB, let c = optC {

}

Swift does execute the body of the IF only if all the optional bindings are properly completed.

More

Another feature of this technique: the assignments are done in order.

So only if a value is properly assigned to a, Swift tries to assign a value to b. And so on.

This allows you to use the previous defined variable/constant like this

if let a = optA, let b = a.optB {

}

In this case (in second assignment) we are safely using a because we know that if that code is executed, then a has been populated with a valid value.

How does swift guard determine true or false when using = operator

The purpose of guard is to assert that a value is non-nil, and to guarantee exit of the current scope if it is. This allows the value to be used throughout the rest of your function and to allow your "golden path" to not be nested within several if-statements.

You can do something similar with an if-let syntax, but it provides no guarantees that the scope must be exited or provide that protected value outside of it's own scope.

guard let name = person["name"] else {
return
}
// name available here!

vs

if let name = person["name"] {
// name available here
} else {
// name not available here
}

// name not available here either

All of this is based on whether the if/guard statements can guarantee the existence of a value, not on truthiness.

How is Swift `if let` evaluated?

Essentially the line is saying, "if you can let the new variable name equal the non-optional version of optionalName, do the following with it". As Martin pointed out, this is called Optional Binding.

The sole purpose of it is to test if an optional variable contains an actual value and bind the non-optional form to a temporary variable. This is the safe way to "unwrap" an optional or in other words, access the value contained in the optional. It is in no way testing for equality of any kind. It is only testing for the existence of a value within an optional.

Setting variable values via an IF statement in Swift

Instead of == you wrote = in your if statement, and by the way here's a shorter version of that code

let locValueDeterminer = Int.random(in: 0...1)

let loc1Value = locValueDeterminer == 0 ? 0.5 : 0.0
let loc2Value = 1.0

Asking what locValueDeterminer == 0 ? 0.5 : 0.0 means?-

it's equivalent to condition ? something : something else

So in a way it translates to:

if locValueDeterminer == 0{
loc1Value = 0.5
}else{
loc1Value = 0.0
}

Checking the value of an Optional Bool

With optional booleans it's needed to make the check explicit:

if boolean == true {
...
}

Otherwise you can unwrap the optional:

if boolean! {
...
}

But that generates a runtime exception if boolean is nil - to prevent that:

if boolean != nil && boolean! {
...
}

Before beta 5 it was possible, but it has been changed as reported in the release notes:

Optionals no longer implicitly evaluate to true when they have a value and false when they do not, to avoid confusion when working with optional Bool values. Instead, make an explicit check against nil with the == or != operators to find out if an optional contains a value.

Addendum: as suggested by @MartinR, a more compact variation to the 3rd option is using the coalescing operator:

if boolean ?? false {
// this code runs only if boolean == true
}

which means: if boolean is not nil, the expression evaluates to the boolean value (i.e. using the unwrapped boolean value), otherwise the expression evaluates to false

Why doesn't using LET as an optional throw an error, as it is an implicit comparison to zero - inconsistency in Swift Intro book?

You are kind of right, it is not consistent, it should not mention Boolean Expression but rather a Logic Value. Here is what the Language Reference says about if:

The value of any condition in an if statement must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in Optional Binding.

Please note that optional binding here is not treated as an expression. It is not an assignment in if like in C. It is just a special case of an if statement that succeeds when the bound value is not nil.

None of this is valid in Swift:

x = y = 10 // () is not convertible to Int
if z = optional { } // type () does not conform to LogicValue
if let z = optional && z > 5 { } // bound value must be of Optional type
if (let z = optional) && z > 5 { } // pattern variable binding cannot appear in expression

Edit:
At first my answer stated that "assignment is not an expression in Swift", but technically that is incorrect. Assignment is an expression, but of type () a.k.a. Void. This is valid Swift:

var v = ()
var x = 0

v = x = 10 // x = 10; v = ()

Edit2:
Just to make this perfectly clear, when you use if let or if var it is not an assignment to an existing variable, a new variable/constant is introduced that is scoped to the inside of the if block:

var x = 0
var y : Int? = 10
if var x = y { // new variable x is introduced
println(x) // prints 10
x = 20 // neither affects y nor 'outer' x
}
if let x = y { // new constant x is introduced
println(x) // prints 10
}
if let y = y { // introduce new y shadowing the original
println(y) // prints 10
}
println(x) // prints 0

//if x = y { } // does not compile


Related Topics



Leave a reply



Submit