Using is and as Keywords

09 Nov 2018

Imagine that you have a number of sub classes (say perhaps of UITableViewCell) and you want some code to do something differntly for each kind of subclass. Recently I came across some code in a project that did it like this:

func whatIs(it: UITableViewCell) -> String {
  if _ as? TableViewCellSubclassA {
      return "This is an instance of Subclass A"
  } else if _ as? TableViewCellSubclassB {
      return "This is an instance of Sublcass B"
  }
  //More code followed in the same form
}

This was relatively hard to read. In addition, I didn’t like the code smell of the _ as? part. That structure in swift has always made me thing that something could have been worded differently. Now, to be fair, in early Swift, I believe this was the only way to really do something like this. However, now we have the is keyword to help us associate a class instance with a class type. So the code can be rewritten somewhat more clearly:

func whatIs(it: UITableViewCell) -> String {
  if it is TableViewCellSubclassA {
    return "This is an instance of Subclass A"
  } else if it is TableViewCellSubclassB {
    return "This is an instance of Subclass B"
  }
  //And on and on
}

NB the is keyword only works with classes and subclasses. If you have other types you still need to use some variation of as.

The use of the is keyword is an improvement for sure over the let _ as? construction as far as readability goes. I was still unhappy with all of the if...else if...else if stuff. I was also noticing that in the legacy code there wasn’t a final else so if a future developer adds a subclass that doesn’t get handled by the code, the system will happy do something undefined (or maybe crash). So, for the final variation that I think addresses the issues of readability and future proofing, I moved to a Swift switch statement and the is keyword with a default case.

func whatIs(it: UITableViewCell) -> String {
  switch it {
  case is TableViewCellSubclassA:
    return "Switch on Subclass A"
  case is TableViewCellSubclassB:
    return "Switch on Subclass B"
  default:
    assertionFailure("A new subclass that isn't handled has been introduced.")
  }
}

The use of an assertion will cause the code to crash during development runs (when it can be addressed) but will not cause the code to crash in a production environment. This way when the future developer adds a subclass they don’t need to remember to also update this function, the compiler will tell them.

If you would like to play with this function and some of the variations I used, I am linking to a playground that demonstrates the code.