We know that there will be time during the game when we don't know how many fingers are being held up, so the variable is optional--it may be an Int or it maybe nil. You will remember from earlier that nil does not mean 0. It is entirely possible that the other player may be holding up zero fingers (that is, a clenched fist) as this is a valid answer. In this scenario, nil represents a lack of knowledge about the number of fingers. To declare this variable as optional, we define the expected type, but with an additional ?:
var numberOfFingersHeldUpByFinn: Int?
In Swift, this is referred to as an optionally wrapped Int. We have wrapped the Int type in the concept of being optional. I am emphasizing this term wrapping because we will need to unwrap this optional type later on. At the start of the game, we don't know how many fingers are being held up, so we assign nil to this variable, which is allowable for optional variables:
numberOfFingersHeldUpByFinn = nil
Once Finn's hand is shown and we know how many fingers he has held up, we can assign that Int value to the variable:
numberOfFingersHeldUpByFinn = 3
Since the variable type is an optional Int, the valid values are either an Int or nil; if we try something of another type, we will get a compiler error:
numberOfFingersHeldUpByFinn = "three" // Doesn't compile because "three" isn't an Int or nil
As we discussed earlier, Swift has a static type system, so the type of a variable can't be changed after it is declared. Therefore, although we have assigned a value of the Int type to the variable, this hasn't changed the variable type to the non-optional Int; its type remains Int?, an optional Int. Since the type is still optional, we can assign it a nil value when Finn puts his hands behind his back again:
numberOfFingersHeldUpByFinn = nil
When we print an optional variable, the output tells us that it is optional, for example, Optional(1):
numberOfFingersHeldUpByFinn = 1
print(numberOfFingersHeldUpByFinn)
You will notice that the compiler highlights an issue that says Expression implicitly coerced from 'Int?' to 'Any' on the print line. We see this because we are passing an option call to the print comment, which is expecting a non-optional value. To solve this issue, we can provide a value to use if our optional value happens to be nil; there is actually a really concise way to do this. The ?? operator can be can be applied after an optional value, and the value to the right of the operator will be used if the optional value is nil; this is called the nil coalescing operator:
print(numberOfFingersHeldUpByFinn ?? "Unknown")
At the end of the game, we want to store the number of fingers that Finn held up during the last round of the game. Since we know that we will play at least one round of the game, we know that there must be a value for the last number of fingers that were held up. Therefore, we declare the lastNumberOfFingersHeldUpByFinn variable as a non-optional Int:
let lastNumberOfFingersHeldUpByFinn: Int = numberOfFingersHeldUpByFinn!
However, our numberOfFingersHeldUpByFinn variable is an optional Int. This is a problem for the compiler and the safeness and stability of our code as we would be applying a value that can be nil at runtime to a variable that is not allowed to be nil. If you remove ! from the preceding statement, that's what we will be doing, and the compiler will complain:
let lastNumberOfFingersHeldUpByFinn: Int = numberOfFingersHeldUpByFinn // Does not compile
To get around this issue, we need to declare that although we initially declared this variable as optional, we know there is a value assigned to it, so we want to declare that this is now non-optional, which is denoted by the !.
In Swift terminology, we are unwrapping the optionality of the variable. Once it is unwrapped, and therefore non-optional, we can assign it to the lastNumberOfFingersHeldUpByFinn variable, which is also non optional.
Beware! Use of this forced unwrapping can be risky. When you forcibly unwrap an optional, as we just did, you are declaring to the compiler that you are sure that there will be a value in that variable at that point in the execution of the code. If for some reason you don't, and the variable is nil, you will get an error at runtime and your execution will terminate. If this code is running in an app, then the app will crash. We will see safer ways to unwrap an optional value in the later chapters.
Take the counting fingers game described earlier. Imagine that we ended the game before playing the first round:
// Start of the game
var numberOfFingersHeldUpByFinn: Int?
// Hand behind his back
numberOfFingersHeldUpByFinn = nil
print(numberOfFingersHeldUpByFinn) // nil
// End of the game
let lastNumberOfFingersHeldUpByFinn: Int = numberOfFingersHeldUpByFinn!
This code will compile and run, but will crash at runtime because at the point that numberOfFingersHeldUpByFinn is assigned to lastNumberOfFingersHeldUpByFinn, the value of numberOfFingersHeldUpByFinn is nil.