Skip to content

Commit 26f9ed2

Browse files
authored
Rename Effect<Output, _> to Effect<Action, _> (#1362)
* Rename Effect<Output, _> -> Effect<Action, _> We'll keep the typealias for the `Publisher` conformance, but given the changes made to TCA for concurrency, `Effect` should typically only be used these days in reducers to feed actions back into the store, and not more generally as publishers of any output. * wip
1 parent 764de87 commit 26f9ed2

File tree

10 files changed

+43
-42
lines changed

10 files changed

+43
-42
lines changed

Sources/ComposableArchitecture/Debugging/ReducerInstrumentation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ extension Effect where Failure == Never {
9898
actionOutput
9999
)
100100
await operation(
101-
Send { output in
101+
Send { action in
102102
os_signpost(
103103
.event, log: log, name: "Effect Output", "%sOutput from %s", prefix, actionOutput
104104
)
105-
send(output)
105+
send(action)
106106
}
107107
)
108108
if Task.isCancelled {

Sources/ComposableArchitecture/Documentation.docc/Articles/Performance.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,10 @@ store.
205205

206206
Reducers are run on the main thread and so they are not appropriate for performing intense CPU
207207
work. If you need to perform lots of CPU-bound work, then it is more appropriate to use an
208-
``Effect``, which will operate in the cooperative thread pool, and then send it's output back into
209-
the system via an action. You should also make sure to perform your CPU intensive work in a
210-
cooperative manner by periodically suspending with `Task.yield()` so that you do not block a thread
211-
in the cooperative pool for too long.
208+
``Effect``, which will operate in the cooperative thread pool, and then send actions back into the
209+
system. You should also make sure to perform your CPU intensive work in a cooperative manner by
210+
periodically suspending with `Task.yield()` so that you do not block a thread in the cooperative
211+
pool for too long.
212212

213213
So, instead of performing intense work like this in your reducer:
214214

Sources/ComposableArchitecture/Documentation.docc/Extensions/EffectDeprecations.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Avoid using deprecated APIs in your app. Select a method to see the replacement
2828

2929
### Combine Integration
3030

31+
- ``Effect/Output``
3132
- ``Effect/init(_:)``
3233
- ``Effect/init(value:)``
3334
- ``Effect/init(error:)``

Sources/ComposableArchitecture/Effect.swift

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import SwiftUI
44
import XCTestDynamicOverlay
55

66
/// The ``Effect`` type encapsulates a unit of work that can be run in the outside world, and can
7-
/// feed data back to the ``Store``. It is the perfect place to do side effects, such as network
7+
/// feed actions back to the ``Store``. It is the perfect place to do side effects, such as network
88
/// requests, saving/loading from disk, creating timers, interacting with dependencies, and more.
99
///
1010
/// Effects are returned from reducers so that the ``Store`` can perform the effects after the
@@ -32,12 +32,12 @@ import XCTestDynamicOverlay
3232
/// > This is only an issue if using the Combine interface of ``Effect`` as mentioned above. If you
3333
/// you are using Swift's concurrency tools and the `.task`, `.run` and `.fireAndForget`
3434
/// functions on ``Effect``, then threading is automatically handled for you.
35-
public struct Effect<Output, Failure: Error> {
35+
public struct Effect<Action, Failure: Error> {
3636
@usableFromInline
3737
enum Operation {
3838
case none
39-
case publisher(AnyPublisher<Output, Failure>)
40-
case run(TaskPriority? = nil, @Sendable (Send<Output>) async -> Void)
39+
case publisher(AnyPublisher<Action, Failure>)
40+
case run(TaskPriority? = nil, @Sendable (Send<Action>) async -> Void)
4141
}
4242

4343
@usableFromInline
@@ -115,8 +115,8 @@ extension Effect where Failure == Never {
115115
/// - Returns: An effect wrapping the given asynchronous work.
116116
public static func task(
117117
priority: TaskPriority? = nil,
118-
operation: @escaping @Sendable () async throws -> Output,
119-
catch handler: (@Sendable (Error) async -> Output)? = nil,
118+
operation: @escaping @Sendable () async throws -> Action,
119+
catch handler: (@Sendable (Error) async -> Action)? = nil,
120120
file: StaticString = #file,
121121
fileID: StaticString = #fileID,
122122
line: UInt = #line
@@ -171,7 +171,7 @@ extension Effect where Failure == Never {
171171
/// }
172172
/// ```
173173
///
174-
/// Then you could attach to it in a `run` effect by using `for await` and sending each output of
174+
/// Then you could attach to it in a `run` effect by using `for await` and sending each action of
175175
/// the stream back into the system:
176176
///
177177
/// ```swift
@@ -199,8 +199,8 @@ extension Effect where Failure == Never {
199199
/// - Returns: An effect wrapping the given asynchronous work.
200200
public static func run(
201201
priority: TaskPriority? = nil,
202-
operation: @escaping @Sendable (Send<Output>) async throws -> Void,
203-
catch handler: (@Sendable (Error, Send<Output>) async -> Void)? = nil,
202+
operation: @escaping @Sendable (Send<Action>) async throws -> Void,
203+
catch handler: (@Sendable (Error, Send<Action>) async -> Void)? = nil,
204204
file: StaticString = #file,
205205
fileID: StaticString = #fileID,
206206
line: UInt = #line
@@ -441,11 +441,11 @@ extension Effect {
441441

442442
/// Transforms all elements from the upstream effect with a provided closure.
443443
///
444-
/// - Parameter transform: A closure that transforms the upstream effect's output to a new output.
444+
/// - Parameter transform: A closure that transforms the upstream effect's action to a new action.
445445
/// - Returns: A publisher that uses the provided closure to map elements from the upstream effect
446446
/// to new elements that it then publishes.
447447
@inlinable
448-
public func map<T>(_ transform: @escaping (Output) -> T) -> Effect<T, Failure> {
448+
public func map<T>(_ transform: @escaping (Action) -> T) -> Effect<T, Failure> {
449449
switch self.operation {
450450
case .none:
451451
return .none
@@ -455,11 +455,9 @@ extension Effect {
455455
return .init(
456456
operation: .run(priority) { send in
457457
await operation(
458-
.init(
459-
send: { output in
460-
send(transform(output))
461-
}
462-
)
458+
Send { action in
459+
send(transform(action))
460+
}
463461
)
464462
}
465463
)

Sources/ComposableArchitecture/Effects/Cancellation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ extension Effect {
3939
()
4040
-> Publishers.HandleEvents<
4141
Publishers.PrefixUntilOutput<
42-
AnyPublisher<Output, Failure>, PassthroughSubject<Void, Never>
42+
AnyPublisher<Action, Failure>, PassthroughSubject<Void, Never>
4343
>
4444
> in
4545
cancellablesLock.lock()

Sources/ComposableArchitecture/Effects/Publisher.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import Combine
55
@available(tvOS, deprecated: 9999.0)
66
@available(watchOS, deprecated: 9999.0)
77
extension Effect: Publisher {
8+
public typealias Output = Action
9+
810
public func receive<S: Combine.Subscriber>(
911
subscriber: S
10-
) where S.Input == Output, S.Failure == Failure {
12+
) where S.Input == Action, S.Failure == Failure {
1113
self.publisher.subscribe(subscriber)
1214
}
1315

14-
var publisher: AnyPublisher<Output, Failure> {
16+
var publisher: AnyPublisher<Action, Failure> {
1517
switch self.operation {
1618
case .none:
1719
return Empty().eraseToAnyPublisher()
@@ -75,7 +77,7 @@ extension Effect {
7577
@available(macOS, deprecated: 9999.0, message: "Wrap the value in 'Effect.task', instead.")
7678
@available(tvOS, deprecated: 9999.0, message: "Wrap the value in 'Effect.task', instead.")
7779
@available(watchOS, deprecated: 9999.0, message: "Wrap the value in 'Effect.task', instead.")
78-
public init(value: Output) {
80+
public init(value: Action) {
7981
self.init(Just(value).setFailureType(to: Failure.self))
8082
}
8183

@@ -147,7 +149,7 @@ extension Effect {
147149
@available(tvOS, deprecated: 9999.0, message: "Use 'Effect.task', instead.")
148150
@available(watchOS, deprecated: 9999.0, message: "Use 'Effect.task', instead.")
149151
public static func future(
150-
_ attemptToFulfill: @escaping (@escaping (Result<Output, Failure>) -> Void) -> Void
152+
_ attemptToFulfill: @escaping (@escaping (Result<Action, Failure>) -> Void) -> Void
151153
) -> Self {
152154
Deferred { Future(attemptToFulfill) }.eraseToEffect()
153155
}
@@ -181,7 +183,7 @@ extension Effect {
181183
@available(macOS, deprecated: 9999.0, message: "Use 'Effect.task', instead.")
182184
@available(tvOS, deprecated: 9999.0, message: "Use 'Effect.task', instead.")
183185
@available(watchOS, deprecated: 9999.0, message: "Use 'Effect.task', instead.")
184-
public static func result(_ attemptToFulfill: @escaping () -> Result<Output, Failure>) -> Self {
186+
public static func result(_ attemptToFulfill: @escaping () -> Result<Action, Failure>) -> Self {
185187
Deferred { Future { $0(attemptToFulfill()) } }.eraseToEffect()
186188
}
187189

@@ -246,9 +248,9 @@ extension Effect {
246248
// due to a bug in iOS 13.2 that publisher will never complete. The bug was fixed in
247249
// iOS 13.3, but to remain compatible with iOS 13.2 and higher we need to do a little
248250
// trickery to make sure the deferred publisher completes.
249-
Deferred { () -> Publishers.CompactMap<Result<Output?, Failure>.Publisher, Output> in
251+
Deferred { () -> Publishers.CompactMap<Result<Action?, Failure>.Publisher, Action> in
250252
try? work()
251-
return Just<Output?>(nil)
253+
return Just<Action?>(nil)
252254
.setFailureType(to: Failure.self)
253255
.compactMap { $0 }
254256
}
@@ -294,7 +296,7 @@ extension Effect where Failure == Error {
294296
watchOS, deprecated: 9999.0,
295297
message: "Throw and catch errors directly in 'Effect.task' and 'Effect.run', instead."
296298
)
297-
public static func catching(_ work: @escaping () throws -> Output) -> Self {
299+
public static func catching(_ work: @escaping () throws -> Action) -> Self {
298300
.future { $0(Result { try work() }) }
299301
}
300302
}

Sources/ComposableArchitecture/Effects/Throttling.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ extension Effect {
2525
return .none
2626
case .publisher, .run:
2727
return self.receive(on: scheduler)
28-
.flatMap { value -> AnyPublisher<Output, Failure> in
28+
.flatMap { value -> AnyPublisher<Action, Failure> in
2929
throttleLock.lock()
3030
defer { throttleLock.unlock() }
3131

@@ -35,7 +35,7 @@ extension Effect {
3535
return Just(value).setFailureType(to: Failure.self).eraseToAnyPublisher()
3636
}
3737

38-
let value = latest ? value : (throttleValues[id] as! Output? ?? value)
38+
let value = latest ? value : (throttleValues[id] as! Action? ?? value)
3939
throttleValues[id] = value
4040

4141
guard throttleTime.distance(to: scheduler.now) < interval else {

Sources/ComposableArchitecture/Effects/Timer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ extension Effect where Failure == Never {
103103
tolerance: S.SchedulerTimeType.Stride? = nil,
104104
on scheduler: S,
105105
options: S.SchedulerOptions? = nil
106-
) -> Self where S.SchedulerTimeType == Output {
106+
) -> Self where S.SchedulerTimeType == Action {
107107
Publishers.Timer(every: interval, tolerance: tolerance, scheduler: scheduler, options: options)
108108
.autoconnect()
109109
.setFailureType(to: Failure.self)
@@ -137,7 +137,7 @@ extension Effect where Failure == Never {
137137
tolerance: S.SchedulerTimeType.Stride? = nil,
138138
on scheduler: S,
139139
options: S.SchedulerOptions? = nil
140-
) -> Self where S.SchedulerTimeType == Output {
140+
) -> Self where S.SchedulerTimeType == Action {
141141
self.timer(
142142
id: ObjectIdentifier(id),
143143
every: interval,

Sources/ComposableArchitecture/Internal/Create.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,18 +171,18 @@ extension Publishers.Create.Subscription: CustomStringConvertible {
171171

172172
extension Effect {
173173
public struct Subscriber {
174-
private let _send: (Output) -> Void
174+
private let _send: (Action) -> Void
175175
private let _complete: (Subscribers.Completion<Failure>) -> Void
176176

177177
init(
178-
send: @escaping (Output) -> Void,
178+
send: @escaping (Action) -> Void,
179179
complete: @escaping (Subscribers.Completion<Failure>) -> Void
180180
) {
181181
self._send = send
182182
self._complete = complete
183183
}
184184

185-
public func send(_ value: Output) {
185+
public func send(_ value: Action) {
186186
self._send(value)
187187
}
188188

Sources/ComposableArchitecture/Internal/Deprecations.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ extension CaseLet {
426426

427427
extension Effect {
428428
@available(*, deprecated)
429-
public var upstream: AnyPublisher<Output, Failure> {
429+
public var upstream: AnyPublisher<Action, Failure> {
430430
self.publisher
431431
}
432432
}
@@ -440,10 +440,10 @@ extension Effect where Failure == Error {
440440
)
441441
public static func task(
442442
priority: TaskPriority? = nil,
443-
operation: @escaping @Sendable () async throws -> Output
443+
operation: @escaping @Sendable () async throws -> Action
444444
) -> Self {
445-
Deferred<Publishers.HandleEvents<PassthroughSubject<Output, Failure>>> {
446-
let subject = PassthroughSubject<Output, Failure>()
445+
Deferred<Publishers.HandleEvents<PassthroughSubject<Action, Failure>>> {
446+
let subject = PassthroughSubject<Action, Failure>()
447447
let task = Task(priority: priority) { @MainActor in
448448
do {
449449
try Task.checkCancellation()

0 commit comments

Comments
 (0)