Why combine operators
Real conditions are rarely a single comparison. A person may get in because of a special status, or because their age falls inside a range. A range already needs two comparisons joined by &&, and the special status adds a third part joined by ||. Swift lets you mix &&, || and ! freely in one expression, as long as you are clear about how the parts group.
Precedence and grouping
When an expression contains several operators, Swift decides the grouping with precedence rules. Comparisons bind tightest, then &&, then ||. So a || b && c means a || (b && c), not (a || b) && c. Both operators evaluate from left to right and skip the right side when the left side already decides the result.
Parentheses override the default. These two expressions use the same pieces and give different answers:
print(7 >= 10 && (5 == 7 || 9 < 12)) // false
print((7 >= 10 && 5 == 7) || 9 < 12) // true
In the first line, the parentheses group 5 == 7 || 9 < 12, which is true. The && then joins it with 7 >= 10, which is false, and an and needs both sides, so the result is false. In the second line, the left group (7 >= 10 && 5 == 7) is false, the right side 9 < 12 is true, and an or needs only one, so the result is true.
The default grouping can hide a bug. Take true || false && false. Because && goes first, this is true || (false && false), which is true. The version (true || false) && false is false. Even when the default grouping is what you want, parentheses make that intent visible to the next reader.
The exercise, step by step
The lesson provides two constants:
let specialStudent: Bool = false
let age: Int = 23
A person is let in when specialStudent is true, or when age is between 18 and 30, both ends included.
- Express the age range. "Between 18 and 30" is two comparisons that must both hold:
age >= 18andage <= 30. Both bounds are inclusive, so use>=and<=, and join them with&&. Swift has no chained form such as18 <= age <= 30. - Add the special-student case. Put
specialStudent ||in front of the range. ABoolcan be used directly as a condition, so there is no need to writespecialStudent == true. - Group the range. Wrap the two age checks in parentheses. The grouping is the same without them, but the parentheses show that the range is one unit.
- Print in both cases. Print
"Let him in!"in theifbody, and add} else {with a print of"Not allowed"for everyone who fails both checks.
let specialStudent: Bool = false
let age: Int = 23
if specialStudent || (age >= 18 && age <= 30) {
print("Let him in!")
} else {
print("Not allowed")
}
With specialStudent set to false and age set to 23, the left side of || is false, so Swift checks the group. Since 23 is at least 18 and at most 30, the group is true and the program prints Let him in!.
Trying other values
Each of these inputs exercises a different path through the condition:
specialStudent = false,age = 17: the age check fails atage >= 18, so the program printsNot allowed.specialStudent = false,age = 18or30: the boundaries count, so it printsLet him in!.specialStudent = false,age = 31: it printsNot allowed.specialStudent = true,age = 50: the left side istrue, so the range is never evaluated, and it printsLet him in!.
Common mistakes
- Using || for the range.
age >= 18 || age <= 30is true for every integer, because every number is at least 18 or at most 30. A range needs&&. - Off-by-one bounds. Writing
age > 18would reject an 18-year-old, which contradicts "between 18 and 30" with inclusive ends. - Grouping the wrong parts.
(specialStudent || age >= 18) && age <= 30turns the special student into someone who still needs to be 30 or younger. - Comparing a Bool to true.
specialStudent == trueworks, butspecialStudentalone is shorter and reads better.
Key takeaways
- Precedence runs from comparisons to
&&to||; parentheses override it. - Add parentheses whenever mixing
&&and||, even if the default grouping would be right. - A range check is two comparisons joined with
&&. - Swift stops evaluating as soon as the result is known.
