Setters and Key Paths

Episode #7 • Mar 12, 2018 • Subscriber-Only

This week we explore how functional setters can be used with the types we build and use everyday. It turns out that Swift generates a whole set of functional setters for you to use, but it can be hard to see just how powerful they are without a little help.

Previous episode
Setters and Key Paths
Next episode
Locked

Unlock This Episode

Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.

Sign in with GitHub

Introduction

In the last episode we explored how functional setters allow us to dive deeper into nested structures to perform transformations while leaving everything else in the structure fixed. We played around with some toy examples, like nested tuples and arrays, and we showed off some pretty impressive stuff, but at the end of the day we aren’t typically transforming tuples. Instead, we have real world data with structs. We want to bring all the ideas from the previous episode into the world of structs so that we can transform a deeply nested struct in a simple, expressive manner. To do this, we are going to leverage Swift’s key paths!

Structs

Here we have a few related structs:

struct Food {
  var name: String
}

struct Location {
  var name: String
}

struct User {
  var favoriteFoods: [Food]
  var location: Location
  var name: String
}

let user = User(
  favoriteFoods: [
    Food(name: "Tacos"),
    Food(name: "Nachos")
  ],
  location: Location(name: "Brooklyn"),
  name: "Blob"
)

References

  • Composable Setters
    Stephen Celis • Sep 30, 2017

    Stephen spoke about functional setters at the Functional Swift Conference if you’re looking for more material on the topic to reinforce the ideas.

  • Semantic editor combinators
    Conal Elliott • Nov 24, 2008

    Conal Elliott describes the setter composition we explored in this episode from first principles, using Haskell. In Haskell, the backwards composition operator <<< is written simply as a dot ., which means that g . f is the composition of two functions where you apply f first and then g. This means if had a nested value of type ([(A, B)], C) and wanted to create a setter that transform the B part, you would simply write it as first.map.second, and that looks eerily similar to how you would field access in the OOP style!

Downloads

Get started with our free plan

Our free plan includes 1 subscriber-only episode of your choice, access to 64 free episodes with transcripts and code samples, and weekly updates from our newsletter.

View plans and pricing