New observer abstraction for future backpressure support and decluttered stack traces #799
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Preface
A
Observer<Value, Error>
abstract base class is introduced. It will replaceSignal<Value, Error>.Observer
as the "currency type" for side effects to be registered with RAS event stream types.There are four reasons behind the persuation of a new abstraction:
Lay the ground work for backpressure support
Backpressure support requires every operator to have extra state for demand management, and a new "subscribed/started" message. This means at the very least:
Signal.Observer
abstraction, if we stick with it, has to be altered.Signal.Event
monads have to be changed (e.g.Signal.Event.map
) — At the barebone level of closure-as-event-sink(Signal.Event) -> Void
, these cannot be extended futher to support the new requirements.Decluttered stack traces
Nominal operator types incidentially improves also the RAS developer experience — symbols in stack traces now clearly attaches to a nominal
Observer
type, e.g.Operators.Map
, while many compiler inserted reabstraction thunks are now gone with the design change.Compiler optimization friendliness to enable untapped performance
The current
Signal.Observer
forces all values to be boxed by theSignal.Event
enum, which is a strict representation of the event grammar in Swift.While this has served us well for almost half a decade, the enum boxing/unboxing by nature requires copying (especially with tag being embedded in unused bits or "extra inhabitants"). This means the prevalent use of
Signal.Event
is unfortunately working against some important Swift compiler optimizations, like passing immutable Large Value argument by reference.Reduce ARC traffic
Some operators like
throttle
anddebounce
require states that persist across events. The current design forces them to be declared externally to the(Signal.Event) -> Void
event sink, and then be captured by the closure context of the event sink. So ARC traffic has to be incurred on both the closure context and each captured references.On a related note on
Signal.Event
, the enum boxing/unboxing can incur defensive ARC traffic, since it is a multi-payload enum potentially packing references.Changes
The new
Observer<Value, Error>
base class.Values are now delivered to
Observer.receive(_:)
, while termination events goes toObserver.terminate(_:)
. The separation allows large values to be optimized as passing-by-reference by the compiler.Signal.Event.Transformation
has an altered signature that is now based onObserver<Value, Error>
, instead of(Signal.Event) -> Void
.A set of operator implementation has been converted as a pilot to nonimal types under the
Operators
namespace.The pilot includes
Operators.Map
,Operator.Filter
andOperator.CompactMap
.Signal.Observer
is now a subclass ofObserver<Value, Error>
as a transitional measure.Out of scope, subsequent work
Operators
namespace.SignalProducer
to acceptObserver<U, E>
instead ofSignal.Observer<U, E>
.Uncertainty
Signal.Observer
is made a subtype ofObserver
to enable gradual transition in the codebase for the time being. But we might end up designing backpressure support in a way that prefers otherwise, becauseSignal
as a hot event stream cannot and will not support backpressure from any demand-limiting observer.Checklist
Updated CHANGELOG.md.