Exploring Optionals

You can continue reading this article or you can choose not to. Similarly, with variables you can have cases where there is a value or it may not have a value which in other words is nil. Optionals are not applicable to all scenarios. To understand this better, read on…

A simple case of Optional

Let’s look at Optionals with a real life scenario, say we are wanting to create an app for a fictional Bank – ABC Bank. This article shall not focus on writing a complete application for Banking, if that is what you are after, you’d better start searching GitHub and the interweb for source code or other articles. The scope of this article is quite simple, we shall explore Optionals with the example of writing a banking app.

So when the banking app is complete and shipped, someone downloads the app, when they do; what account number do you think they have? The account number does not exist because this somebody might or might not have an account. Due to this ambiguity, there might be or not be an account number. Do you think that if the account does not exist, you can simply assign them a default account of 0000000000 (10 zero’s, all valid accounts should be 10 digits) ? In the old days this is exactly what programmers would have done, assign a default value and then change it later. However with Optionals we can do better, 0000000000 is a value and just because we do not use this value it does not mean that this should be used as the default value. What if due to some error the code fails to update the account to the proper number? This account is now assigned the default account number. Secondly, this will also persist to the database, and if this is a unique number, then you cannot have multiple simultaneous accounts as they will fail because only one record can have that value. So instead of all this, we can simply assign the value of nil to the account number. What this indicates is that there is no value assigned to the account number and later in the code we can check for this and assign a proper account number.

In terms of code, this would be represented as

struct Account {
  var accountNumber: String?
  var balance: Double

  init(accountNumber: String? = nil, balance: Double = 0.0) {
    self.accountNumber = accountNumber
    self.balance = balance
  }
}

then we could simply create a new Customer with

 let newAccount = Account()

because the default values on the function signature are applied, which are nil for account number and 0.00 for the balance.
The structure could be more complex than the one illustrated above, the sample code above is just to illustrate the point of Optionals and their usage.

Why not have Balance as NIL too?

You might ask that very question, why is the balance not nil, wouldn’t it make sense that all of the values are nil at start? Just because you have a hammer doesn’t mean that everything is a nail. No single solution can be applied across for everything and in addition to that, setting the balance to 0.00 is a perfectly valid starting balance. Then you could apply transactions to get the current balance, if you had the balance as nil, what would you apply the transactions to? You cannot do arithmetic with nil.

Now, let us consider that we also have a listing of accounts, so the customer might have more than one type of account with the bank and on the Dashboard we want to show these account. What would be the best way to hold the information?
A simple way to look at things is what do we want to hold, Account or Accounts ? If what we want to hold is plural, not a single value, then we need to use a collection (an Array, a Dictionary, etc) and since we are storing multiple accounts, we need it to contain values of type Account.

var accounts: [Account]

what should this be? should it be an optional or not? Many developers set the array to an optional with the default value as nil. I do not understand the logic, maybe they are trying to save a few bytes of storage allocated for the array. However I believe that it is OK to have it as an array setup as

var accounts: [Account] = []

this will create a blank array that holds values of type Account . If you want to know how many accounts are held in that array, the property .count gives us that answer. For arrays that do not have any data in them, the .count returns 0 indicating that there are no accounts.

We can then iterative though each account using

for account in accounts {
  print("Balance for : \(account.accountNumber) is \(account.balance)")
}

UH OH!!
We have a problem because when the accountNumber is nil, it will display on the dashboard the string literal nil than the account number, so we need to weed out the accounts that have not as yet set the accountNumbers. It can be managed with a simple if condition as,

for account in accounts {
  if let accountNumber = account.accountNumber {
    print("Balance for : \(account.accountNumber) is \(account.balance)")
  }
}

what we did with the if is called unwrapping it, we unwrapped the value in an Optional to check if it was nil or a valid value? If it was a valid value, we printed the message otherwise we skipped that account on to the next one, Looping through the list of accounts held in accounts.

Dashboards

If we are creating a banking app and displaying accounts, then we also need to have a dashboard, a screen where we can get a quick snapshot of the balances and totals. Let’s try to add the totals, this is achieved simply via one of the two methods, the old way is looping through the accounts and adding the balances to a total. The other way is to use functional programming and adding the totals using reduce.

var total: Double = 0.0
for account in accounts {
  if let accountNumber = account.accountNumber {
    print("Balance for : \(account.accountNumber) is \(account.balance)")
    total += account.balance
  }
}
print("Total : \(total)")

or

let total = accounts.reduce(0, {$0 + $1.balance})

That’s all we have time for today folks

This brings us towards the end of this article on Optionals, Hope this gave you an understanding of what Optionals are and how they are used in real life scenarios. If you want to read a bit more on the ? ! side of Optionals which we avoided using other than in the definition of the structure, you can head to my other article http://howto.oz-apps.com/2017/11/solving-code-issues-with-writing-more.html

I can leave you with this that you can use extensions to enhance the functionality around Optionals like in the article referenced above to execute code on the absence or presence of a value. Something on the lines of

for account in accounts {
  account.accountNumber.ifNotNil { accountNumber in 
    print("Balance for \(accountNumber) is \(account.balance)")
  }
}

Till the next time … here’s some code for you to play with

struct Account {
    var accountNumber: String?
    var balance: Double
    
    init(accountNumber: String? = nil, balance: Double = 0.0) {
        self.accountNumber = accountNumber
        self.balance = balance
    }
}

var accounts:[Account] = []


accounts = [
    Account(),
    Account(accountNumber: "000000001", balance: 123.45),
    Account(accountNumber: "000000010", balance: 15.75),
    Account(),
    Account(accountNumber: "000000100", balance: 125678.93),
    Account(),
    Account(accountNumber: "000001000", balance: 1.87),
]


print(accounts.count)

let total_reduce = accounts.reduce(0, {$0 + $1.balance})
print(total_reduce)

var total:Double = 0.0
for account in accounts {
    if let accountNumber = account.accountNumber {
        total += account.balance
        print("Balance for :\(accountNumber) is \(account.balance)")
    }
}
print("Total : \(total)")


let validAccounts = accounts.flatMap({return $0.accountNumber})
print(validAccounts.count, accounts.count)
print(validAccounts)
Views All Time
Views All Time
759
Views Today
Views Today
1
Posted in Article, Basics and tagged , , .