Reducer Protocol: Composition, Part 2

Episode #204 • Sep 12, 2022 • Subscriber-Only

The new reducer protocol has improved many things, but we’re now in an awkward place when it comes to defining them: some are conformances and some are not. We’ll fix that with inspiration from SwiftUI and the help of a new protocol feature.

Composition, Part 2
Introduction
00:05
Inspiration from SwiftUI
01:43
Primary associated types
14:55
Result builder type inference
21:34
Next time: dependencies
29:43

Unlock This Episode

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

Introduction

We’ve now got a ReducerProtocol in place along with a ReducerBuilder, and things are looking really great. We see that we can still accomplish everything we were doing in the old style, but we are getting all new tools for simplifying and organizing our features built in the library.

But there’s still something not quite right with our VoiceMemos reducer. It is really strange that in order to implement its reduce method we are constructing a big, composed reducer just to turn around it hit its reduce method to actually perform the work. The whole reason we are doing this strange dance is because we are trying to move away from defining our reducers as variables defined at the file-scope, which is an admirable goal since file-scope variables seem to put strain on the compiler. But it still feels like we haven’t quite cracked the ergonomics of this pattern yet.

It feels like there’s actually two styles of implementing reducers. First, there are the leaf node features, such as the RecordingMemo and VoiceMemo features. In those situations we aren’t composing together and integrating multiple domains. We are just implementing the bare logic for those features in a reduce method.

But then there are also the more complicated features that do need to integrate multiple domains together, and in those situations we prefer to compose things together using result builder syntax.

Amazingly, it’s possible to augment the ReducerProtocol so that we can support both of these styles in one package. Then, at the moment of conforming a type to the ReducerProtocol, we can decide which style do we want to implement. Are we implementing some simple standalone logic, or are we composing many things together?

Let’s see what it takes to make this happen.

This episode is for subscribers only.

Subscribe to Point-Free

Access this episode, plus all past and future episodes when you become a subscriber.

See plans and pricing

Already a subscriber? Log in

References

SE-0215: Conform Never to Equatable and Hashable

Matt Diephouse • Thursday May 24, 2018

The Swift evolution proposal that extended Never to conform to Equatable and Hashable. The Never type, sometimes called a “bottom” type, cannot be instantiated, and can theoretically conform to most protocols.

SE-0346: Lightweight same-type requirements for primary associated types

Pavel Yaskevich, Holly Borla, Slava Pestov • Friday Mar 11, 2022

The Swift evolution proposal that introduced primary associated types to protocols, which are what unlocked the Composable Architecture’s ability to allow reducer compositions to be more ergonomically defined.

Function builder cannot infer generic parameters even though direct call to `buildBlock` can

Dan Zheng, Holly Borla, Doug Gregor, et al. • Sunday Apr 26, 2020

A forum discussion about result builder generic inference and how it differs from the rest of Swift.

Downloads