Hey @mayoff, great find! It does seem like pretty much anything you can do with the scheduler .animation operator you can also do with the publisher .animation operator you have defined here.
We have found a few small ergonomic differences between the two styles that may interest you. By tying the animation to the scheduler we can make the call site more obvious when the operator is used incorrectly. For example, this:
apiClient.fetch()
.receive(on: DispatchQueue(label: "background.queue").animation())
.map(AppAction.response)
Is obviously incorrect because you would never want to call withAnimation on a background queue. Doing so doesn't seem to error in any obvious ways, but it doesn't cause things to animate.
On the other hand, doing this with publisher animations:
apiClient.fetch()
.animation()
.receive(on: DispatchQueue.main)
.map(AppAction.response)
Is a little more subtle in its wrongness. If apiClient.fetch() emits output on a background thread, then .animation() will silently stop working. The way to correct this would be to make sure .animation() is called after .receive(on:):
apiClient.fetch()
- .animation()
.receive(on: DispatchQueue.main)
+ .animation()
.map(AppAction.response)
It also seems that calling withAnimation on a background thread may secretly cause problems down the road, and so it may be very difficult to track it back to this one small subtlety.
Another tiny ergonomic difference is that passing an argument can be a little more flexible at the call site than method chaining. For example, if you wanted some logic around specifying an animation versus using whatever the current animation context is:
apiClient.fetch()
.receive(
on: someCondition
? DispatchQueue.main.animation()
: DispatchQueue.main
)
.map(AppAction.response)
To do this with the publisher operator you would need something like:
var effect = apiClient.fetch()
if someCondition {
effect = effect.animation()
}
return effect
.receive(on: DispatchQueue.main)
.map(AppAction.response)
Again, these are pretty small ergonomics differences, and there may be others. We're not entirely sure one is definitively better than the other. Maybe both have their use cases. We're going to continue thinking about it, and please let us know if you discover anything new!
Thanks again for bringing this up!