Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass state to SwitchStore.init view builder #2029

Merged
merged 11 commits into from
Apr 10, 2023
Merged

Conversation

stephencelis
Copy link
Member

@stephencelis stephencelis commented Apr 6, 2023

Rather than rely on many, many overloads of SwitchStore.init to strictly accept only CaseLets and an optional, final Default view, let's introduce a single initializer without constraints that is passed the current state whenever the case changes. This state can be switched on and route to the appropriate view via CaseLet.

The pros:

  • We get exhaustive switching at compile time.

  • We get more flexibility in the view layer. Previously, any customization needed to be pushed into the CaseLet builder, but now CaseLet can freely apply view modifiers.

  • We can deprecate and eventually remove the many, many initializer overloads, and hopefully slim down binary size in the process, and improve view builder compile times when dealing with SwitchStore. We can also deprecate and eventually remove Default.

  • The current overloads only support up to 10 cases, but now we'd support any number.

The cons:

  • It's slightly more verbose and repetitive. You have a SwitchStore and then a switch inside it with many cases with CaseLets inside them, and the case .screen: is followed by CaseLet(/State.screen, ...).

  • One is free to extract the state's associated value(s) and use it to render a view, but this view will be inert and will not re-render if the value it depends on changes in the store. This can lead to some surprises, but we can document against the pattern, and maybe in the future we can use something like macros to prevent this from being possible.

    SwitchStore(store) {
      switch $0 {
      case let .loggedIn(loggedInState):
        Text("Welcome, \(loggedInState.user.name)!")
        // 👆 This will not re-render if the user's name changes.
      // ...
      }
    }
  • You can still get things wrong if you're not careful: there's nothing enforcing that the case you switch on is the same case you send to CaseLet, so case .screenA: CaseLet(/State.screenB, ...) is possible. While unlikely, it's still a copy-paste error in waiting.

    Edit: While this is possible, we've added a runtime warning that will emit when it happens.

Rather than rely on many, many overloads of `SwitchStore.init` to
strictly accept only `CaseLet`s and an optional, final `Default` view,
let's introduce a single initializer without constraints that is passed
the current state whenever the case changes. This state can be switched
on and route to the appropriate view via `CaseLet`.

The pros:

  * We get exhaustive switching at compile time.

  * We get more flexibility in the view layer. Previously, any
    customization needed to be pushed into the `CaseLet` builder, but
    now `CaseLet` can freely apply view modifiers.

  * We can deprecate and eventually remove the many, many initializer
    overloads, and hopefully slim down binary size in the process, and
    improve view builder compile times when dealing with `SwitchStore`.
    We can also deprecate and eventually remove `Default`.

The cons:

  * It's slightly more verbose and repetitive. You have a `SwitchStore`
    and then a `switch` inside it with many `case`s with `CaseLet`s
    inside them, and the `case .screen:` is followed by
    `CaseLet(/State.screen, ...)`.

  * One is free to extract the state's associated value(s) and use it to
    render a view, but this view will be inert and will not re-render if
    the value it depends on changes in the store. This can lead to some
    surprises, but we can document against the pattern, and maybe in the
    future we can use something like macros to prevent this from being
    possible.

  * You can still get things wrong if you're not careful: there's
    nothing enforcing that the `case` you switch on is the same case you
    send to `CaseLet`, so `case .screenA: CaseLet(/State.screenB, ...)`
    is possible. While unlikely, it's still a copy-paste error in
    waiting.
Comment on lines 15 to 18
SwitchStore(self.store) { state in
switch state {
case .login:
CaseLet(state: /TicTacToe.State.login, action: TicTacToe.Action.login) { store in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this diff I'm wondering what function the SwitchStore provides

  • Instead of SwitchStore+CaseLet could an IfLetStore perform the same work?
  • If you want completeness over all cases, use a ViewStore scoped to state?

Then, thinking about this in terms of navigation, we're often peeling off a single enum case in different parts of the view, not necessarily constructing a complete switch statement in one place. Should we think about other conditional views the same way? Again, maybe IfLetStore is the only tool needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want completeness over all cases, use a ViewStore scoped to state?

If done naively, such a view store would observe all mutations to child state in each associated value, which could easily lead to performance problems and other glitches. SwitchStore automatically de-dupes to only re-render when the case changes using the Swift runtime metadata.

@denysdanyliukboosters
Copy link

Hi! I wanted to ask if these changes will remove the limit on the number of CaseLet inside SwitchStore?

@mbrandonw
Copy link
Member

Hi! I wanted to ask if these changes will remove the limit on the number of CaseLet inside SwitchStore?

Yes, that should be the case. The only limit will be how many cases are allowed in a @ViewBuilder context, and I believe that is unlimited since it can just nest as many _ConditionalContents as it needs.

@oliverfoggin
Copy link

oliverfoggin commented Apr 7, 2023

Just to check my understanding... is the intended use case like...

SwitchStore {
  switch $0 {
  case .someCase:
    CaseLet { store in
      SomeView(store)
    }
  }
}

?

Not sure if I understood the full code change reqs from this change.

Thanks

(Also forgive poor code, on my phone with only my left hand at the moment 😬)

@mbrandonw
Copy link
Member

Hi @oliverfoggin, that is correct. You will be passed state in SwitchStore so that you can switch on it, and then in each case of that switch you will construct a CaseLet. The diff looks like this:

 SwitchStore {
+  switch $0 {
+  case .someCase:
     CaseLet { store in
       SomeView(store)
     }
   }
 }

@tgrapperon
Copy link
Contributor

tgrapperon commented Apr 7, 2023

This is an idea I already pitched in the past, so I'm all-in with the change! The unobserved state is unfortunate, but it seems indeed that macros will allow to automatically derive an enum like:

enum DestinationStore {
  case a(StoreOf<A>)
  case b(StoreOf<B>)
}

which will allow to replace CaseLet. It is also possible that even SwitchStore will be able to be replaced!. In any case, this PR goes in the right direction. The current locking of overloads to CaseLet members is indeed inconvenient when you want to append additional modifiers, because you can only do this on their content rather than on CaseLet themselves.

@jefflewis
Copy link

I used a switch store that I had to break apart into 3 different switch stores due to having too many cases. So if this removes that limitation (as previously commented), I'm more than happy to have a few more case lines while also getting compile time checks on the used cases. 🙌

@kugel3
Copy link

kugel3 commented Apr 8, 2023

I think it would be useful if the original post actually showed concrete examples of the change.

And what does the bullet point below mean? That the "top elements" of the SwitchStore no longer have to be of CaseLet type, so now you can put modifiers on them, not just inside?

We get more flexibility in the view layer. Previously, any customization needed to be pushed into the CaseLet builder, but now CaseLet can freely apply view modifiers.

Also, I wonder if it wouldn't be possible to somehow do the switching as a scoping operation? I mean when we scope, we expose the entire state, transform it and pass it into a child, without even dealing with the question of unwanted redrawing. With SwitchStore we can't do that, because it's a view.

@rhysm94
Copy link
Contributor

rhysm94 commented Apr 10, 2023

Being able to support more than 10 cases would be a phenomenal change!
I use TCACoordinators in a project which uses SwitchStore inside the main router view, and one of the coordinated flows has considerably more than 10 views (and can’t easily be simplified 😬), so I have to hack around it using Group, with loads of Default views.
Being able to remove that, and being able to switch at compile time, would dramatically simplify this code!

@stephencelis
Copy link
Member Author

stephencelis commented Apr 10, 2023

I think it would be useful if the original post actually showed concrete examples of the change.

@kugel3 The original post shows an example in a counter example, and @mbrandonw posted a small diff example a little before your reply here, but the basic change is that state is passed along and switched on before handing off to CaseLet, rather than a flat list of CaseLets terminated by an optional Default:

 SwitchStore(self.store.scope(state: \.child, action: Parent.Action.child) {
+  switch $0 {
+  case .foo:
     CaseLet(/Child.State.foo, action: Child.Action.foo) { store in
       FooView(store: store)
     }
+  case .bar:
     CaseLet(/Child.State.bar, action: Child.Action.bar) { store in
       BarView(store: store)
     }
-  Default {
+  default:
     Text("DefaultView") 
   }
 }

This provides all the pros listed in the original post, along with some gotchas listed under cons.

And what does the bullet point below mean? That the "top elements" of the SwitchStore no longer have to be of CaseLet type, so now you can put modifiers on them, not just inside?

Yes exactly, as well as Group them, introduce other views, etc.

On main, SwitchStore disallows arbitrary views. It can only be unmodified CaseLet views, one after the other, and an optional final Default view. This PR would remove that restriction and you can basically render what you want (though if you introduce if or switch conditions that render a CaseLet in the wrong place (e.g. you switch and handle case .foo but return a CaseLet(/.bar) from that branch), you'll get a runtime warning.

Also, I wonder if it wouldn't be possible to somehow do the switching as a scoping operation? I mean when we scope, we expose the entire state, transform it and pass it into a child, without even dealing with the question of unwanted redrawing. With SwitchStore we can't do that, because it's a view.

I'm not quite sure what you're suggesting here. Can you sketch out some sample code?

@stephencelis stephencelis marked this pull request as ready for review April 10, 2023 17:49
@stephencelis
Copy link
Member Author

Reception seems to be positive, and we think this is the direction, so gonna merge! Feel free to continue the conversation if you have questions, comments, or concerns, though consider starting a discussion for more visibility.

@stephencelis stephencelis merged commit 4192a84 into main Apr 10, 2023
8 checks passed
@stephencelis stephencelis deleted the switch-store-underload branch April 10, 2023 18:37
renovate bot added a commit to cgrindel/rules_swift_package_manager that referenced this pull request Jul 6, 2023
…ure to from: "0.55.0" (#452)

[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
|
[pointfreeco/swift-composable-architecture](https://togithub.com/pointfreeco/swift-composable-architecture)
| minor | `from: "0.51.0"` -> `from: "0.55.0"` |

---

### Release Notes

<details>
<summary>pointfreeco/swift-composable-architecture
(pointfreeco/swift-composable-architecture)</summary>

###
[`v0.55.0`](https://togithub.com/pointfreeco/swift-composable-architecture/releases/tag/0.55.0)

[Compare
Source](https://togithub.com/pointfreeco/swift-composable-architecture/compare/0.54.1...0.55.0)

#### What's Changed

- Added: The Composable Architecture's SwiftUI bindings integration has
been greatly improved, with better support for view state bindings
([pointfreeco/swift-composable-architecture#2215).
- Added: `Store.send` and `Store.withState` have been added, for sending
actions to stores and accessing store state without needing a view store
([pointfreeco/swift-composable-architecture#2222).
- Added: `ReducerProtocol.onChange`
([pointfreeco/swift-composable-architecture#2226).
- Added: `EffectOf<Reducer>` convenience type alias to
`EffectTask<Reducer.Action>`
([pointfreeco/swift-composable-architecture#2237).
- Updated: `swiftui-navigation` has been bumped to 0.8.0
([pointfreeco/swift-composable-architecture#2239).
- Improved: `TestStore` failure messages have been improved
([pointfreeco/swift-composable-architecture#2227,
[pointfreeco/swift-composable-architecture#2236).
- Fixed: `ForEachStore` no longer force-unwraps its cached value,
avoiding crashes in race condition-heavy code (thanks
[@&#8203;ohitsdaniel](https://togithub.com/ohitsdaniel),
[pointfreeco/swift-composable-architecture#1036).
- Fixed: Addressed a few Xcode 15 warnings (Swift 6 errors)
([pointfreeco/swift-composable-architecture#2213).
- Deprecated: `Effect.cancel(ids:)` has been deprecated
([pointfreeco/swift-composable-architecture#2221).
- Infrastructure: Documentation improvements (thanks
[@&#8203;ccxla](https://togithub.com/ccxla),
[pointfreeco/swift-composable-architecture#2185,
[pointfreeco/swift-composable-architecture#2184,
[pointfreeco/swift-composable-architecture#2183;
[@&#8203;tomu28](https://togithub.com/tomu28),
[pointfreeco/swift-composable-architecture#2209;
[@&#8203;alexhunsley](https://togithub.com/alexhunsley),
[pointfreeco/swift-composable-architecture#2204;
[@&#8203;oronbz](https://togithub.com/oronbz),
[pointfreeco/swift-composable-architecture#2173;
[pointfreeco/swift-composable-architecture#2225;
[pointfreeco/swift-composable-architecture#2238).

#### New Contributors

- [@&#8203;tomu28](https://togithub.com/tomu28) made their first
contribution in
[pointfreeco/swift-composable-architecture#2209
- [@&#8203;alexhunsley](https://togithub.com/alexhunsley) made their
first contribution in
[pointfreeco/swift-composable-architecture#2204
- [@&#8203;ohitsdaniel](https://togithub.com/ohitsdaniel) made their
first contribution in
[pointfreeco/swift-composable-architecture#1036

**Full Changelog**:
pointfreeco/swift-composable-architecture@0.54.1...0.55.0

###
[`v0.54.1`](https://togithub.com/pointfreeco/swift-composable-architecture/releases/tag/0.54.1)

[Compare
Source](https://togithub.com/pointfreeco/swift-composable-architecture/compare/0.54.0...0.54.1)

#### What's Changed

- Fixed: A regression introduced in 0.54.0 prevented some Composable
Architecture projects from building in release due to a Swift compiler
bug. We have removed some `@inlineable` attributes to work around this
bug
([pointfreeco/swift-composable-architecture#2201).
While we don't anticipate noticeable runtime performance regressions in
release builds of applications, please report any issues you may see.
- Infrastructure: Added Hindi (Indian) translation of README.md (thanks
[@&#8203;akashsoni01](https://togithub.com/akashsoni01),
[pointfreeco/swift-composable-architecture#2171)
- Infrastructure: Documentation updates and fixes (thanks
[@&#8203;Sajjon](https://togithub.com/Sajjon),
[pointfreeco/swift-composable-architecture#2150;
[@&#8203;tatsuz0u](https://togithub.com/tatsuz0u),
[pointfreeco/swift-composable-architecture#2155;
[@&#8203;hmhv](https://togithub.com/hmhv),
[pointfreeco/swift-composable-architecture#2152;
[@&#8203;MarshalGeazipp](https://togithub.com/MarshalGeazipp),
[pointfreeco/swift-composable-architecture#2154;
[@&#8203;Ryu0118](https://togithub.com/Ryu0118),
[pointfreeco/swift-composable-architecture#2153;
[@&#8203;Czajnikowski](https://togithub.com/Czajnikowski),
[pointfreeco/swift-composable-architecture#2157;
[@&#8203;kristofferjohansson](https://togithub.com/kristofferjohansson),
[pointfreeco/swift-composable-architecture#2159;
[@&#8203;jaesung-0o0](https://togithub.com/jaesung-0o0),
[pointfreeco/swift-composable-architecture#2160;
[pointfreeco/swift-composable-architecture#2161;
[@&#8203;takehilo](https://togithub.com/takehilo),
[pointfreeco/swift-composable-architecture#2165;
[@&#8203;nickkohrn](https://togithub.com/nickkohrn),
[pointfreeco/swift-composable-architecture#2168
[pointfreeco/swift-composable-architecture#2169;
[@&#8203;d-date](https://togithub.com/d-date),
[pointfreeco/swift-composable-architecture#2174;
[@&#8203;oronbz](https://togithub.com/oronbz),
[pointfreeco/swift-composable-architecture#2175,
[pointfreeco/swift-composable-architecture#2176,
[pointfreeco/swift-composable-architecture#2177;
[@&#8203;devMinseok](https://togithub.com/devMinseok),
[pointfreeco/swift-composable-architecture#2180;
[@&#8203;ccxla](https://togithub.com/ccxla),
[pointfreeco/swift-composable-architecture#2181;
[@&#8203;filblue](https://togithub.com/filblue),
[pointfreeco/swift-composable-architecture#2188;
[@&#8203;thomastosoni](https://togithub.com/thomastosoni),
[pointfreeco/swift-composable-architecture#2190).

#### New Contributors

- [@&#8203;Sajjon](https://togithub.com/Sajjon) made their first
contribution in
[pointfreeco/swift-composable-architecture#2150
- [@&#8203;MarshalGeazipp](https://togithub.com/MarshalGeazipp) made
their first contribution in
[pointfreeco/swift-composable-architecture#2154
- [@&#8203;takehilo](https://togithub.com/takehilo) made their first
contribution in
[pointfreeco/swift-composable-architecture#2165
- [@&#8203;nickkohrn](https://togithub.com/nickkohrn) made their first
contribution in
[pointfreeco/swift-composable-architecture#2168
- [@&#8203;akashsoni01](https://togithub.com/akashsoni01) made their
first contribution in
[pointfreeco/swift-composable-architecture#2171
- [@&#8203;d-date](https://togithub.com/d-date) made their first
contribution in
[pointfreeco/swift-composable-architecture#2174
- [@&#8203;oronbz](https://togithub.com/oronbz) made their first
contribution in
[pointfreeco/swift-composable-architecture#2175
- [@&#8203;devMinseok](https://togithub.com/devMinseok) made their first
contribution in
[pointfreeco/swift-composable-architecture#2180
- [@&#8203;ccxla](https://togithub.com/ccxla) made their first
contribution in
[pointfreeco/swift-composable-architecture#2181
- [@&#8203;thomastosoni](https://togithub.com/thomastosoni) made their
first contribution in
[pointfreeco/swift-composable-architecture#2190

**Full Changelog**:
pointfreeco/swift-composable-architecture@0.54.0...0.54.1

###
[`v0.54.0`](https://togithub.com/pointfreeco/swift-composable-architecture/releases/tag/0.54.0)

[Compare
Source](https://togithub.com/pointfreeco/swift-composable-architecture/compare/0.53.2...0.54.0)

#### What's Changed

- Added: All-new navigation tools for presenting child features
([pointfreeco/swift-composable-architecture#1945,
[pointfreeco/swift-composable-architecture#1944,
[pointfreeco/swift-composable-architecture#2048).

See the associated
[documentation](https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/navigation)
and
[tutorial](https://pointfreeco.github.io/swift-composable-architecture/main/tutorials/meetcomposablearchitecture/#navigation)
for how to incorporate these tools into your applications today!

- Added: `TestStore.assert`, for asserting state changes on
non-exhaustive stores at any time
([pointfreeco/swift-composable-architecture#2123).

- Fixed: Ensure that a test store helper runs on the main actor
([pointfreeco/swift-composable-architecture#2117).

- Added: Ukrainian translation of TCA's README (thanks
[@&#8203;barabashd](https://togithub.com/barabashd),
[pointfreeco/swift-composable-architecture#2121).

- Infrastructure: DocC organization
([pointfreeco/swift-composable-architecture#2118).

- Infrastructure: Ensure CI runs library tests in release
([pointfreeco/swift-composable-architecture#2120).

- Fix assertion values by
[@&#8203;tomassliz](https://togithub.com/tomassliz) in
[pointfreeco/swift-composable-architecture#2128

- Infrastructure: Documentation fixes (thanks
[@&#8203;tomassliz](https://togithub.com/tomassliz),
[pointfreeco/swift-composable-architecture#2124,
[pointfreeco/swift-composable-architecture#2128;
[@&#8203;jaesung-0o0](https://togithub.com/jaesung-0o0),
[pointfreeco/swift-composable-architecture#2144).

#### New Contributors

- [@&#8203;tomassliz](https://togithub.com/tomassliz) made their first
contribution in
[pointfreeco/swift-composable-architecture#2124
- [@&#8203;jaesung-0o0](https://togithub.com/jaesung-0o0) made their
first contribution in
[pointfreeco/swift-composable-architecture#2144

**Full Changelog**:
pointfreeco/swift-composable-architecture@0.53.2...0.54.0

###
[`v0.53.2`](https://togithub.com/pointfreeco/swift-composable-architecture/releases/tag/0.53.2)

[Compare
Source](https://togithub.com/pointfreeco/swift-composable-architecture/compare/0.53.1...0.53.2)

#### What's Changed

- Make `Send` sendable
([pointfreeco/swift-composable-architecture#2112)
- When test exhaustivity is off, `receive` now waits for the expected
action rather than taking the first action (thanks
[@&#8203;alex-reilly-pronto](https://togithub.com/alex-reilly-pronto),
[pointfreeco/swift-composable-architecture#2100)
- Fix typo in the "Meet the Composable Architecture" (thanks
[@&#8203;redryerye](https://togithub.com/redryerye),
[pointfreeco/swift-composable-architecture#2114)
- Fix compile error in Xcode <14.3 (thanks
[@&#8203;hj56775](https://togithub.com/hj56775),
[pointfreeco/swift-composable-architecture#2115)

#### New Contributors

- [@&#8203;alex-reilly-pronto](https://togithub.com/alex-reilly-pronto)
made their first contribution in
[pointfreeco/swift-composable-architecture#2100
- [@&#8203;redryerye](https://togithub.com/redryerye) made their first
contribution in
[pointfreeco/swift-composable-architecture#2114
- [@&#8203;hj56775](https://togithub.com/hj56775) made their first
contribution in
[pointfreeco/swift-composable-architecture#2115

**Full Changelog**:
pointfreeco/swift-composable-architecture@0.53.1...0.53.2

###
[`v0.53.1`](https://togithub.com/pointfreeco/swift-composable-architecture/releases/tag/0.53.1)

[Compare
Source](https://togithub.com/pointfreeco/swift-composable-architecture/compare/0.53.0...0.53.1)

#### What's Changed

- Fixed: A regression was introduced in 0.53.0 where `TestStore.init`'s
`prepareDependencies` was called twice. It will not be called just a
single time again
([pointfreeco/swift-composable-architecture#2111).
- Infrastructure: Added a "Meet the Composable Architecture" tutorial
([pointfreeco/swift-composable-architecture#2107,
[pointfreeco/swift-composable-architecture#2109).
- Infrastructure: Docs fixes (thanks
[@&#8203;Ryu0118](https://togithub.com/Ryu0118),
[pointfreeco/swift-composable-architecture#2110)

**Full Changelog**:
pointfreeco/swift-composable-architecture@0.53.0...0.53.1

###
[`v0.53.0`](https://togithub.com/pointfreeco/swift-composable-architecture/releases/tag/0.53.0)

[Compare
Source](https://togithub.com/pointfreeco/swift-composable-architecture/compare/0.52.0...0.53.0)

#### What's Changed

- Added: `Store.init` and `TestStore.init` now take reducer builders
([pointfreeco/swift-composable-architecture#2087).
    ```swift
    // Before:
    Store(
      initialState: Feature.State(),
      reducer: Feature()
    )

    // After:
    Store(initialState: Feature.State()) {
      Feature()
    }
    ```

- Changed: `SwitchStore` has gotten some quality-of-life improvements
([pointfreeco/swift-composable-architecture#2029).
- `SwitchStore.init` can now take the initial enum state so that it can
be switched over exhaustively. This initializer also relaxes certain
compile-time constraints previously requiring only `CaseLet` views and
an optional, trailing `Default` view.
- `CaseLet` can now omit the `state` parameter label, making it more
consistent with other APIs, like `Reducer.ifCaseLet`.
- The older `SwitchStore` and `CaseLet` initializers have been
soft-deprecated along with the `Default` view.

        ```swift
        // Before:
        SwitchStore(self.store) {
CaseLet(state: /App.State.loggedIn, action: App.Action.loggedIn) {
loggedInStore in
            LoggedInView(store: loggedInStore)
          }
CaseLet(state: /App.State.loggedOut, action: App.Action.loggedOut) {
loggedOutStore in
            LoggedOutView(store: loggedOutStore)
          }
        }

        // After:
        SwitchStore(self.store) {
switch $0 { // Can now switch over initial state for exhaustivity at
compile time
          case .loggedIn:
CaseLet(/App.State.loggedIn, action: App.Action.loggedIn) {
loggedInStore in
              LoggedInView(store: loggedInStore)
            }
.buttonStyle(.plain) // Can now render arbitrary views/modifiers in the
view builder
          case .loggedOut:
CaseLet(/App.State.loggedOut, action: App.Action.loggedOut) {
loggedOutStore in
              LoggedOutView(store: loggedOutStore)
            }
          }
        }
        ```

- Changed: `WithViewStore.debug` has been renamed to
`WithViewStore._printChanges` for consistency with
`Reducer._printChanges`
([pointfreeco/swift-composable-architecture#2101).

- Fixed: `EffectTask.publisher` now properly escapes dependencies
accessed within it
([pointfreeco/swift-composable-architecture#1988).

- Fixed: `Reducer._printChanges()` is no longer disabled in tests
([pointfreeco/swift-composable-architecture#1995).
This allows it to be used for debugging purposes during test runs.

- Changed: The internal `Task.megaYield` tool, for more predictably
testing concurrent code, is now configurable via the
`TASK_MEGA_YIELD_COUNT` environment variable
([pointfreeco/swift-composable-architecture#2064).

- Improved: The output format of `WithViewStore._printChanges()` has
been improved
([pointfreeco/swift-composable-architecture#1973).

- Improved: Runtime warnings will now emit XCTest failures in test code
rather than in app code
([pointfreeco/swift-composable-architecture#2059).

- Deprecated: Type-based cancel IDs have been deprecated
([pointfreeco/swift-composable-architecture#2091).
Use hashable values, instead.

- Deprecated: The actionless overload of `Store.scope(state:)` has been
deprecated in favor of the `observe` parameter on view stores
([pointfreeco/swift-composable-architecture#2097).

- Deprecated: `Effect.task` and `Effect.fireAndForget` have been
soft-deprecated in favor of `Effect.run`
([pointfreeco/swift-composable-architecture#2099).

- Infrastructure: Added test coverage for child/parent effect
cancellation behavior
([pointfreeco/swift-composable-architecture#1970).

- Infrastructure: Clean up effect cancellation logic
([pointfreeco/swift-composable-architecture#1977).

-   Infrastructure: Miscellaneous documentation/formatting fixes:

Fixed missing `action` parameter in `ForEachStore` documentation (thanks
[@&#8203;m-housh](https://togithub.com/m-housh),
[pointfreeco/swift-composable-architecture#1998).

Number fact tutorial fix (thanks
[@&#8203;siliconsorcery](https://togithub.com/siliconsorcery),
[pointfreeco/swift-composable-architecture#1962).

`BindingAction` fix (thanks
[@&#8203;Ryu0118](https://togithub.com/Ryu0118),
[pointfreeco/swift-composable-architecture#2019).

`withTaskCancellation(id:)` fix (thanks
[@&#8203;bjford](https://togithub.com/bjford),
[pointfreeco/swift-composable-architecture#2049).

Formatting fix (thanks
[@&#8203;mooyoung2309](https://togithub.com/mooyoung2309),
[pointfreeco/swift-composable-architecture#2056).

Update 'bindable state' to 'binding state' (thanks
[@&#8203;Jager-yoo](https://togithub.com/Jager-yoo),
[pointfreeco/swift-composable-architecture#2054).

- Infrastructure: Added Russian README translation (thanks
[@&#8203;artyom-ivanov](https://togithub.com/artyom-ivanov),
[pointfreeco/swift-composable-architecture#2014).

- Infrastructure: Added Polish README translation (thanks
[@&#8203;MarcelStarczyk](https://togithub.com/MarcelStarczyk),
[pointfreeco/swift-composable-architecture#2040).

-   Infrastructure: Bump dependencies.

- Infrastructure: Bump Xcode demo project settings
([pointfreeco/swift-composable-architecture#2042).

- Infrastructure: Clean up and test `TestStore.skipInFlightEffects`
([pointfreeco/swift-composable-architecture#2057).

- Infrastructure: CI updates
([pointfreeco/swift-composable-architecture#2060).

- Infrastructure: Document how exhaustive vs. non-exhaustive test stores
work
([pointfreeco/swift-composable-architecture#2096).

#### New Contributors

- [@&#8203;m-housh](https://togithub.com/m-housh) made their first
contribution in
[pointfreeco/swift-composable-architecture#1998
- [@&#8203;siliconsorcery](https://togithub.com/siliconsorcery) made
their first contribution in
[pointfreeco/swift-composable-architecture#1962
- [@&#8203;artyom-ivanov](https://togithub.com/artyom-ivanov) made their
first contribution in
[pointfreeco/swift-composable-architecture#2014
- [@&#8203;Ryu0118](https://togithub.com/Ryu0118) made their first
contribution in
[pointfreeco/swift-composable-architecture#2019
- [@&#8203;MarcelStarczyk](https://togithub.com/MarcelStarczyk) made
their first contribution in
[pointfreeco/swift-composable-architecture#2040
- [@&#8203;mooyoung2309](https://togithub.com/mooyoung2309) made their
first contribution in
[pointfreeco/swift-composable-architecture#2056

**Full Changelog**:
pointfreeco/swift-composable-architecture@0.52.0...0.53.0

###
[`v0.52.0`](https://togithub.com/pointfreeco/swift-composable-architecture/releases/tag/0.52.0)

[Compare
Source](https://togithub.com/pointfreeco/swift-composable-architecture/compare/0.51.0...0.52.0)

#### What's Changed

- Added: Support for `XCTModify` and non-exhaustive testing
([pointfreeco/swift-composable-architecture#1939).
- Added: Library reducer operators are now annotated with
`@warn_unqualified_access` to prevent accidental bugs
([pointfreeco/swift-composable-architecture#1950).
- Added: `Effect.publisher` for bridging effects from Combine
([pointfreeco/swift-composable-architecture#1958).
- Changed: `Effect<Action>.Send` has been renamed to `Send<Action>`
(thanks [@&#8203;tgrapperon](https://togithub.com/tgrapperon),
[pointfreeco/swift-composable-architecture#1930).
- Changed: Dependencies have been bumped to their latest versions to
encourage adoption of bug fixes
([pointfreeco/swift-composable-architecture#1964).
- Fixed: Dependencies are no longer recursively propagated over effects
([pointfreeco/swift-composable-architecture#1954).
- Fixed: `TestStore.init` now calls `prepareDependencies` in a
`withDependencies` block
([pointfreeco/swift-composable-architecture#1955).
- Infrastructure: Fix UI test for `ForEach` bindings
([pointfreeco/swift-composable-architecture#1933).
- Infrastructure: Add missing documentation to `Store.init` (thanks
[@&#8203;kristofferjohansson](https://togithub.com/kristofferjohansson),
[pointfreeco/swift-composable-architecture#1940).
- Infrastructure: DocC fixes
([pointfreeco/swift-composable-architecture#1942,
[pointfreeco/swift-composable-architecture#1956).
- Infrastructure: Update latest version documentation link in README
(thanks [@&#8203;yimajo](https://togithub.com/yimajo),
[pointfreeco/swift-composable-architecture#1943)
- Infrastructure: Fix `.forEach()` documentation (thanks
[@&#8203;finestructure](https://togithub.com/finestructure),
[pointfreeco/swift-composable-architecture#1957).
- Infrastructure: Documentation grammar fixes (thanks
[@&#8203;bjford](https://togithub.com/bjford),
[pointfreeco/swift-composable-architecture#1963)

#### New Contributors

-
[@&#8203;kristofferjohansson](https://togithub.com/kristofferjohansson)
made their first contribution in
[pointfreeco/swift-composable-architecture#1940

**Full Changelog**:
pointfreeco/swift-composable-architecture@0.51.0...0.52.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/cgrindel/rules_swift_package_manager).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNS4xNDQuMiIsInVwZGF0ZWRJblZlciI6IjM1LjE0NC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants