1. The Bool type: “yes/no” as a normal type
If you are just starting to program, it is easy to think: “Well, I can write 1 for “yes” and 0 for “no”.” Some languages even tolerate that. Swift does not. And, honestly, it is right: “yes/no” is a separate meaning, a separate data category, and it deserves a separate type.
Bool is the type that has only two possible values: true (truth) and false (falsehood). It is used to store the result of checks: “is the number greater than zero?”, “is the command equal to exit?”, “is the year within the valid range?”. With this type, code becomes more readable: you do not have to keep in your head that 1 means “yes” and 0 means “no”; you see it directly in the value.
Imagine that Bool is a switch. It is either on (true) or off (false). And today we are learning to make such “switches” out of numbers and strings.
true and false: declare boolean values and print them
First, the simplest thing: boolean values can be written directly by hand. This is useful for tests and for getting used to the type. Yes, in real life you will more often get Bool from comparisons, but it is better to start with something you can touch without magic.
let isSwiftFun: Bool = true
let isDebugMode: Bool = false
print("isSwiftFun = \(isSwiftFun)") // isSwiftFun = true
print("isDebugMode = \(isDebugMode)") // isDebugMode = false
Here it is important to get used to two things right away. First, Bool is a normal type: you can write it explicitly (: Bool), or you can let Swift infer it automatically. Second, Bool is printed beautifully through string interpolation — we already know how to do that.
You can also omit the explicit type — that will even look nicer:
let isLoggedIn = true
let hasPremium = false
print(isLoggedIn) // true
print(hasPremium) // false
So far everything looks too simple, almost suspiciously so. Relax: the real value of Bool begins where we compute it instead of writing it by hand.
2. Number comparisons: getting Bool from Int
Comparison is the main way to get Bool. We take two values (most often numbers) and ask: “are they equal?”, “is one greater than the other?”, “is it not less?”. The answer is always boolean: either yes or no.
Order comparison operators: <, >, <=, >=
These operators answer the question “who is bigger/smaller”. For integers (Int), they work exactly as you would expect.
A reference table (so your brain does not pretend it “already remembers”):
| Operator | Reads as | Example | Result |
|---|---|---|---|
|
less than | |
|
|
greater than | |
|
|
less than or equal to | |
|
|
greater than or equal to | |
|
Mini-example:
let a = 10
let b = 5
let isGreater = a > b
let isNotLess = a >= b
print("isGreater = \(isGreater)") // isGreater = true
print("isNotLess = \(isNotLess)") // isNotLess = true
Pay attention: the expression a > b is not a command, but a value. It is evaluated and becomes Bool. We can store it in a variable, print it, and pass it further somewhere else (in the next lecture, into if).
Range check without ranges
Later we will discuss more convenient things, but right now we can check whether a number is “inside” some interval using two comparisons:
let x = 7
let isInRange = x >= 1 && x <= 10
print(isInRange) // true
Stop. The logical operator && appeared here — the logical “AND”. According to today’s plan, it will be covered in detail in the next lecture about logical operations, but the idea itself can already be seen now: often one comparison is only half of a condition, and with the second half we “complete” the meaning. If you do not want to think about && yet, do not think about it: in this lecture we are focusing specifically on the fact that a comparison produces Bool.
4. Equality and inequality: == and !=
If an order comparison answers “who is bigger”, equality answers “are the values the same?”. And this is such a common operation that it appears everywhere: from checking a command to comparing calculation results.
== means “equal”, and != means “not equal”
An example with numbers:
let n = 7
let isSeven = n == 7
let isNotSeven = n != 7
print("isSeven = \(isSeven)") // isSeven = true
print("isNotSeven = \(isNotSeven)") // isNotSeven = false
== is the equality comparison operator, and it returns Bool.
String comparison: String can also be compared for equality
With strings, we are usually interested in plain equality/inequality: did the user enter the word exit, does the password match, is the command equal to help.
let command = "exit"
let isExit = command == "exit"
print(isExit) // true
And an important nuance: string comparison is case-sensitive and sensitive to spaces.
let command = "Exit"
print(command == "exit") // false
We have not yet studied “input normalization” (trimming spaces, lowercased(), etc.), so for now we simply note the fact: a string is compared literally.
5. The most common situation: comparing what the user entered
In practice, comparison is rarely done on “perfect” constants. Usually the data comes from the user, and a user is a creative being. Today we will carefully assemble a small pattern: “input → conversion to a normal type → comparison”.
readLine() returns String?, so first we make a String
If we are comparing a string, let us first get a plain string through ??.
let input = readLine() ?? ""
let isEmpty = input == ""
print("input = '\(input)'") // e.g.: input = 'hello'
print("isEmpty = \(isEmpty)") // e.g.: isEmpty = false
We are not branching here at all, we are just printing the result. But the meaning is already useful: we got a boolean “sensor” named isEmpty.
If we want to compare as a number, two sources of “non-number” appear
When we read a number from the console, two unpleasant things may happen.
- First: readLine() returned nil (for example, input ended).
- Second: there is a string, but it is not a number ("abc").
That is why in basic tasks it is convenient to do this:
let text = readLine() ?? ""
let n = Int(text) ?? 0
let isEven = n % 2 == 0
print("n = \(n), isEven = \(isEven)") // e.g.: n = 12, isEven = true
Here n % 2 gives the remainder after division by 2, and the comparison == 0 turns this into Bool. The result is a neat fact: “is the number even?”
Yes, using 0 as the default is a questionable decision, because the user may have entered garbage and we quietly pretended they entered zero. At the early stage of learning, that is acceptable: we are training the mechanics of types. Later we will learn to handle errors and Optional more honestly.
6. Careful conditions
Comparisons can easily turn into a mess. Not because Swift is bad, but because we are human and sometimes write code as if we are rushing for the last bus. There are a few simple rules that surprisingly quickly improve readability.
Boolean variables should read like a question
If a variable stores a Bool, its name should sound like a question. Then the code reads almost like text.
Compare:
let age = 20
let flag = age >= 18
print(flag) // true
and
let age = 20
let isAdult = age >= 18
print(isAdult) // true
In the second case, your head does not even need to work hard: “isAdult” is the question “adult?”. This is especially important when later you will write if isAdult { ... } and read it like a sentence.
Separate “calculation” and “message”
Beginners often try to cram everything into one line. Compact — yes. Clear — not always. It is better to calculate first, then print.
let a = 10
let b = 3
let isDivisible = a % b == 0
print("a divisible by b: \(isDivisible)") // a divisible by b: false
In such examples, you practice a good habit: a comparison expression yields Bool, Bool can be stored, printed, and later used as a condition.
7. Example: a skeleton for a console application
So that the examples are not just a random collection of numbers, let us imagine the simplest console program that we will gradually “bring to life” as the course progresses. Let us call it LibraryMini: for now it does nothing “useful”, but it already reads input and computes properties.
Scenario: the user enters a command and a publication year. We do not branch yet (that is not allowed), but we compute the key points and print them.
let command = readLine() ?? ""
let yearText = readLine() ?? ""
let year = Int(yearText) ?? 0
let isExitCommand = command == "exit"
let isYearPositive = year > 0
let isModern = year >= 2000
print("isExitCommand = \(isExitCommand)") // e.g.: true
print("isYearPositive = \(isYearPositive)")
print("isModern = \(isModern)")
Why is this useful, even though “nothing happens”? Because this is the right architectural idea: first we turn input into clear facts (Bool), and only then decide what to do. In the next lecture we will do exactly that: take these boolean variables and start branching.
8. Typical mistakes when working with Bool and comparisons
Mistake #1: confusing = and ==.
= is assignment: “put the value into the variable.” == is comparison: “are the two values equal?” and the result will be Bool. The confusion looks funny until the compiler saves you. But if you get used to thinking correctly now, there will be less pain later.
Mistake #2: trying to use a number as a condition instead of Bool.
In some languages 0 is false, and 1 is true. In Swift this is not allowed: a condition must be a boolean expression. So instead of “magic zeros and ones” we write explicit comparisons like n > 0 or n == 1. It is a little longer, but more readable and without hidden rules. And exactly this style of boolean checks is considered basic for if/guard, for example in expressions like guard x == 0, ....
Mistake #3: comparing different types “by eye”.
A very common attempt is to compare Int with a string, because “the string contains a number anyway”. But for Swift these are different types, and it will not guess your intentions. The correct path is to convert the input to the needed type: let n = Int(text) ?? 0, and only then compare.
Mistake #4: comparing readLine() directly and forgetting about String?.
readLine() returns String?, which means the value may be absent. That is why the habit of “normalize first” with ?? "" is not nitpicking, but protection against extra problems. And only after that do we compare string with string.
Mistake #5: naming boolean variables with names like flag, tmp, b1.
Such names quickly turn code into a riddle: “flag of what?”. It is much better to get used to is…, has…, can… right away: isExitCommand, hasTicket, canEnter. Then even without if the code already reads like human text, and the transition to branching in the next lecture will be as natural as possible.
GO TO FULL VERSION