Unlock This Episode
Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.
We’ve now spent a couple episodes exploring “functional setters”: functions that allow us to build up expressive, immutable data transformations from small units. We’ve explored how they compose together in surprising ways to let us make changes to deeply-nested values: changes that are generally cumbersome to make. And we’ve leveraged a wonderful and unique Swift feature, key paths, to pluck setters out of thin air for properties on our classes and structs.
Setters are an incredibly powerful and broadly useful tool, but the current functions we’ve written have some rough edges when it comes to using them. They’re also not the most performant things in the world: because setters are immutable, they create copies of their values every step of the way. Today we’ll smooth out those rough edges and explore how we can use Swift’s value mutation semantics to make things more performant.
We previously saw that functions
(inout A) -> Voidand functions
(A) -> Void where A: AnyObjectcan be composed the same way. Write
^in terms of
AnyObject. Note that there is a specific subclass of
WritableKeyPathfor reference semantics.
Our episode on UIKit styling was nothing more than setters in disguise! Explore building some of the styling functions we covered using both immutable and mutable setters, specifically how setters compose over sub-typing in Swift, and how setters compose between roots that are reference types, and values that are value types.
concatas single-type composition, but this doesn’t mean we’re limited to a single generic parameter! Write a version of
concatthat allows for composition of value transformations of the same input and output type. This should allow for
prop(\UIEdgeInsets.top) <> prop(\.bottom)as a way of assigning both
bottomthe same value at once.
Define an operator-free version of setters using
concatfrom our episode on composition without operators. Define an
updatefunction that combines the semantics of
withand the variadic convenience of
In the Haskell Lens library,
setare defined as infix operators
.~. Define these operators and explore what their precedence should be, updating some of our examples to use them. Do these operators tick the boxes?
We open sourced the Overture library to give everyone access to functional compositions, even if you can’t bring operators into your codebase.
Stephen spoke about functional setters at the Functional Swift Conference if you’re looking for more material on the topic to reinforce the ideas.
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
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!