Replies: 2 comments
-
Hi @jtbergman, unfortunately Swift macros are not capable of this, as described. Macros only see the syntax they are attached to, and cannot make changes to other types. There may be ways to approximate this, but it opens a up a lot of questions around ergonomics and feasibility. For example, the @Reducer
struct Feature {
…
enum Action {
case tap
case response(String)
}
…
}
// Generates code:
protocol FeatureAction_{some-unique-identifier} {
associatedtype State
associatedtype Action
func reduceTap(into state: inout State) -> Effect<Action>
func reduceResponse(into state: inout State, payload: String) -> Effect<Action>
}
extension Feature: FeatureAction_{some-unique-identifier} {} That would then force you to provide implementations of those methods in the But there are two problems. First, when macros generate code that cause compilation errors (such as the case with the above), the errors are notoriously hidden in Xcode and often times just crash the compiler. And I would even be surprised if you get autocomplete on these methods. The sad fact is the more complex the macro, the worse user experience it is using it. And second, the question is what do we actually do with these methods? Right now they aren't called by anyone, so who is going to invoke it? Well, of course the macro can just generate more code: // more code generated by @Reducer
let core = Reduce<State, Action> { state, action in
switch action {
case .tap:
self.reduceTap(into: &state)
case .response(let payload):
self.reduceResponse(into: &state, payload: payload)
}
} …but then who calls that code? It somehow needs to be integrated into the var body: some ReducerOf<Self> {
core
// More reducers and operators
} …but you will have to remember to do that yourself, and if you forget your app will just silently break. And macros are not capable of inserting this code for you, and even if they were, the vast majority of the time you need to chain operators onto this reducer, such as This is just my initial thoughts on the topic. I haven't personally considered these kinds of changes to reducers, and so I may have missed something. Overall, I think a lot more thought and experimentation needs to go into the topic before any decisions can be made. |
Beta Was this translation helpful? Give feedback.
-
Problem
After adding
forEach(_:action:)
to my reducer that operates onIdentifiedArrayOf
I keep getting issues with "type checking unable to complete in reasonable time." To resolve this, I have each action handler out into its own function that returns anEffect<Self.Action>
and call that from the reducerbody
.Another minor ergonomic issue with the framework is that each
Action
is essentially a function. The breadcrumbs at the top of an Xcode file allow you to see all definitions in the file, but with TCA you typically only getbody
for all of this functionality.Proposal
I'm unsure what macros can and cannot do, but would it be possible to support syntax like this?
My thought is this would automatically add an
Action
case namedmyReducerAction
with all of the params except the first one. An additional nice feature would be if you could skip definingenum Action
andvar body
when using this syntax. This would be some nice sugar for what I'm already doing. It would also encourage others to writeReducers
as separate functions.Again, not sure this is possible, but it would be good for ergonomics.
Beta Was this translation helpful? Give feedback.
All reactions