Perhaps, it is undesirable to throw errors in some situations. Suppose, you have a dictionary storing a user’s data. Some of the data may be mandatory/required, whereas the presence/absence of some data is left to the user’s discretion. He/she may or may not choose to share some information.
In the case of essential data that absolutely must be present, we want errors to be thrown if that data is missing. However, other pieces of data may not be critical to our program. If they are available, that is good. If they are missing, that is fine. We don’t want errors to be thrown or for the program to crash.
You may get data from different sources other than declarations made explicitly by you. Or perhaps, you do declare and initialize a dictionary with the appropriate keys, but somewhere later in the code, some key(s) may be removed by some function/method. If a key is missing, you may want to customize how you handle that omission. Do you want to throw an error (essential data) or do you want to ignore the omission because the missing data is not critical? Optionals can give you flexibility to handle both situations.
Consider the example in which a user is required to share his/her name, but may share or omit the nickname.
var user1: [String: String] = [ "name": "Jack Weaver", "nickname": "Speedy" ]
var user2: [String: String] = [ "name": "Janet Flanagan" ]
for user in [user1, user2] {
print("Name: \(user["name"]!)")
if let nick = user["nickname"] {
print("Nickname: \(nick)")
}
print()
}
# Output
Name: Jack Weaver
Nickname: Speedy
Name: Janet Flanagan
In this example, the name is mandatory. We don’t want complicated or verbose syntax to establish the absence/presence of the "name"
key. We are going to proceed under the assumption that this key exists. If it is missing, an error will be thrown. This is desired, because we don’t want anonymous users. Force unwrapping of the optional allows us to do exactly this. All we need for forced unwrapping is !
. That doesn’t overly complicate the syntax.
print(user["name"]!)
Suppose, trying to access a key of the dictionary didn’t result in an Optional. Instead, the value was returned directly. Absence of key would cause an error. That is satisfactory for the mandatory keys, but no so for the non-essential keys. We don’t want an error/crash when we try to access the "nickname"
key. We could do something like:
if user.keys.contains("nickname") {
print("Nickname: \(user["nickname"]!)")
}
This will work, but it will affect speed and efficiency of your program. The .keys
method will create an array of the keys of the dictionary, and .contains
will then traverse the array until either the key is found or you reach the end of the array. You may be adding and removing keys in various places in your program, so the keys of the dictionary aren’t fixed. Every time you want to check whether a key exists or not before accessing it, you will have to create an array of keys and then traverse it. The Optional avoids this issue.
if let nick = user["nickname"] {
print("Nickname: \(nick)")
}
Instead of creating an array of keys and then searching through it, we simply go ahead and try to access the key. If the key is present in the dictionary, we can safely unwrap it as above. If the key is absent, the program doesn’t throw an error or crash.
If accessing the key of a dictionary directly returned the value associated with that key, then yes it will work nicely for the situations when we are absolutely sure that the key exists. But, for the non-essential keys, trying to directly return a value would cause an error, and we would have to use something like user.keys.contains("nickname")
to avoid this with consequences for speed and efficiency.
The Optional offers us a nice balance. If the key is guaranteed to be present, then simply adding a !
allows us to unwrap the optional without much hassle. If the key may or may not be present, then an Optional doesn’t cause an error and allows us to safely unwrap it (if it is present) or do something else (if it is absent) without adverse effects on speed or efficiency.