How to work with Optional Values

Last week, I was talking to a developer and the one things that stuck in my head from that conversation was that "Ruby is an opinionated language". The word Opinionated meant something quite different to me for years. However it simply means that it is inflexible and expects the users to do things in a particular way. So in that broad classification, the Swift compiler is quite opinionated. But what would you do if you wanted to have values that were optional?

Swift Optionals

In Swift, you can easily create optional values by declaring them with the question mark at the end, like so
var name: String?
now name is an optional, it means that the variable called name can hold a value of type String OR nil. If you had declared it without the question mark, it would expect a value of type String only and the compiler would complain about nil.
print("The name is " + name)
so to make sure that this works, you have to unwrap the optional using the exclamation mark, like so
print("The name is " + name!)
but this can cause crashes if the values are nil.

Checking for nils

You can check for nil the old way before unwrapping it.
if name != nil { print("The name is " + name!) }

Swift way to manage Optionals

Swift has a better way to manage optionals which even includes unwrapping the optionals using the if let like so
if let name = name {
    print("The name is " + name)
 }

Overusing Optionals

Optionals are quite useful and handy, but then like most things it can be used or ab_used. I read an article on the net about optionals recently that spoke about how it can be used. The example used was about creating a new object of type Person and passing it a firstName and lastName with the middleName as optional. The problem with this example was that while it was fine for examples, it is not the best way to deal with in the real world.

Let's look at that quickly and briefly

struct Person {
   var firstName:String
   var lastName: String
   var middleName: String?
 }

 let me = Person(firstName:"Jayant", lastName:"Varma", middleName:nil)

 var displayName: String {
   if let middleName = middleName {
      return firstName + " " + middleName + " " + lastName
   } else {
      return firstName + " " + lastName
   }
 }

Alternative to this solution

In my opinion, you should not set the middleName as nil and more so, you should never have to create a new Person object with setting nil for some variables. Here's the proposed solution which is an alternative to the one above.

struct Person {
    var firstName: String
    var middleName: String
    var lastName: String

    init(firstName: String, lastName: String, middleName: String = "") {
      self.firstName = firstName
      self.middleName = middeName
      self.lastName = lastName
    }

    var fullName: String {
      if middleName == "" {
          return firstName + " " + lastName        
      } else {
          return firstName + " " + middleName + " " + lastName
      }
    }
  }

The advantage of this solution over the previous one is / are
1. You can create the Person object with or without a middleName, you do not have to set the middleName as nil
var me = Person(firstName:"Jayant", lastName:"Varma")
  print(me.fullName) 
OR
var andy = Person(firstName:"Andrew", lastName:"Carter", middleName:"Bailey")
  print(andy.fullName)

and both are taken care of automagically. Where the full name including the middle name is displayed where ever it is set. So if say a middle name is set for me, it is displayed.
me.middleName = "C"
  print(me.fullName)


Next steps in Swift

This example is one of the most common things that you would come across when writing software, however using optionals (nil) values are not necessarily the solution in all scenarios. Next time around, we can look at guard and error handling using try..catch blocks.


Reference

The article mentioned above can be found at http://swift.ayaka.me/posts/2015/10/5/optional

Comments

Popular Posts