Implementing Custom Subscripts in Swift

Learn how to extend your own types with subscripts, allowing you to index into them with simple syntax just like native arrays and dictionaries. By Mikael Konutgan.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 2 of this article. Click here to view the first page.

Comparing Subscripts, Properties And Functions

Subscripts are similar to computed properties in many regards:

  • They consist of a getter and setter.
  • The setter is optional, meaning a subscript can be either read-write or read-only.
  • A read-only subscript doesn’t explicitly state get or set; the entire body is a getter.
  • In the setter, there’s a default parameter newValue with a type that equals the subscript’s return type. You typically only declare this parameter when you want to change its name to something other than newValue.
  • Users expect subscripts to be fast, preferably O(1), so keep them short and sweet!

disguise

The major difference with computed properties is that subscripts don’t have a property name per se. Like operator overloading, subscripts let you override the language-level square brackets [] usually used for accessing elements of a collection.

Subscripts are similar to functions in that they have a parameter list and return type, but they differ on the following points:

  • Subscript parameters don’t have external names by default. If you want to use them, you’ll need to explicitly add them.
  • Subscripts cannot use inout or default parameters. However, variadic (...) parameters are allowed.
  • Subscripts cannot throw errors. This means a subscript getter must report errors through its return value and a subscript setter cannot throw or return any errors at all.

Adding a Second Subscript

There is one other point where subscripts are similar to functions: they can be overloaded. This means a type can have multiple subscripts, as long as they have different parameter lists or return types.

Add the following code after the existing subscript definition in Checkerboard:

subscript(x: Int, y: Int) -> Square {
  get {
    return self[(x: x, y: y)]
  }
  set {
    self[(x: x, y: y)] = newValue
  }
}

This code adds a second subscript to Checkerboard that two integers rather than a Coordinate tuple. Notice how the second subscript is implemented using the first through self[(x: x, y: y)].

Try out this new subscript by adding the following lines to the end of the playground:

print(checkerboard[1, 2])
checkerboard[1, 2] = .white
print(checkerboard)

You should see the piece at (1, 2) change from red to white.

Where to Go From Here?

You can download the completed playground for this tutorial here.

Why not extend this game a bit further with some gameplay logic and turn this into a playable checkers game? Here’s a nice checkerboard collection view cell class to get you started.

Now that you’ve added subscripts to your toolkit, look for opportunities to use them in your own code. When used properly, they can make your code more readable and intuitive. That being said, you don’t always want to revert to subscripts. If you’re writing an API, your users are used to using subscripts to access elements of an indexed collection. Using them for other things will likely feel unnatural and forced.

For more details, check out the subscripts chapter of The Swift Programming Language by Apple for further information on subscripts.

If you have any questions or comments, please leave them below!

Mikael Konutgan

Contributors

Mikael Konutgan

Author

Over 300 content creators. Join our team.