Why is `Scope` a top level Reducer? (and `BindingReducer` for that matter)

I was wondering why Scope the reducer is done the way it is as a top level reducer and not as a function on Reducer.

Other reducers are done as a function. .ifLet .ifCaseLet etc...

I know that in those cases the order matters. So there is a case for forcing that constraint. But for instance with BindingReducer() the order also matters as it needs to run first. So wouldn't it make sense for this to be a .binding like it was before the ReducerProtocol update?

And then, if we're doing that could we not also do .scope(...). I feel like this would match a lot more with how the store on the view side of things is scoped.

1 Like

Hi @Fogmeister, as you noted, the main reason is that there is no order to preserve. Also, BindingReducer does not have an order requirement. There can be times you may want the value before the binding is applied, and so we have that flexibility with a top-level reducer.

Further, we found that type inference and autocomplete worked better with the Scope style. Typically you can do Scope(state: \. and autocomplete figures out what key paths are available based on the surrounding builder context. Whereas .pullback(state: \. has no such context.

And finally, there's a chance we may even move store.scope in the direction of Scope rather than the other way around. This discussion shows why we might want that, and we've started experimenting with baking it deep into the library.


Ah, ok.

That makes sense. And I think the idea to move the store.scope more in the same direction of the reducer Scope is a good call.

I guess whichever way they go it's good to get as much consistency between the store scoping and the reducer scoping. So either way is good.