# \[Accepted with revision\] SE-0395: Observability

**URL:** <https://forums.swift.org/t/accepted-with-revision-se-0395-observability/66760>\
**Category:** Announcements\
**Created:** [August 15, 2023, 12:26am UTC](https://forums.swift.org/t/accepted-with-revision-se-0395-observability/66760 "2023-08-15T00:26:07Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![tcldr](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tcldr/32/24405_2.png) [@tcldr](https://forums.swift.org/u/tcldr)\
**Post date:** [August 15, 2023, 7:36am UTC](https://forums.swift.org/t/accepted-with-revision-se-0395-observability/66760/4 "2023-08-15T07:36:02Z")

</div>

For the record, this review – or any of the previous proposal threads – are still yet to offer a rationale as to why a purported generalised mechanism for observation generates events _exclusively_ on a `willSet` basis.

Whilst this fulfils the very specific requirements of Swift UI, for a generalised observation mechanism this seems highly unusual and is a major limitation.

The workaround of re-creating a `didSet` notification through an async `Task` will quickly be revealed as an anti-pattern for the reasons expressed below.

For context, here's some further detail on the issue as discussed in the latest proposal thread:

* * *

The `willSet` variant is great for allowing SwiftUI to perform its 'before changes' render pass and schedule its 'after changes' render pass for the end of the current event loop cycle, but for anything else that needs to happen between these two points – we're stuck.

Really, the `onChange` parameter of the `withObservationTracking(_:onChange:)` function should be called `willChange` to better reflect the semantics of the API.

A participant in [the old pitch thread](https://forums.swift.org/t/pitch-observation-revised/63757/92) laid out their [questions surrounding] the current API:

> [@\[Pitch\] Observation (Revised)](https://forums.swift.org/t/pitch-observation-revised/63757/92):
>
> how are we to observe an @Observable from something that is not a SwiftUI view - something that may itself be Observable.
> 
> My use case may not be common, but when using Combine, I often broke the pipelines into smaller pieces and various structs would subscribe to upstream publishers and modify or join them before republishing them. In this way we could create small pieces that did one thing that could be appropriately named and flexibly assembled. I was thinking we could do the same with @Observables upstream that we might assemble with things from async algorithms etc.
> 
> Then again, I may be trying to hold it wrong.

As I summarised in the pitch thread, the two recommendations we have right now are to a) use computed properties, or b) use this pattern:

> [@\[Second review\] SE-0395: Observability](https://forums.swift.org/t/second-review-se-0395-observability/65261/5):
>
> However if you do have a need to (in non SwiftUI scenarios) to do something similar then the use for the `withObservationTracking` (note; it got changed to a free floating function).
> 
> ```swift
> func resetObservationOnExternalObservable() {
> withObservationTracking {
> self.dependentProperty = "\(external.indirectlyObservedProperty). Woohoo!"
> } onChange: { [weak self] in
> // The onChange is fired on the willSet side of things - so the reset needs to be called asynchronously to prevent a recursion and also update after the property changes.
> Task { @MainActor in
> self?.resetObservationOnExternalObservable()
> }
> }
> }
> 
> ```

However, method A suffers from unnecessary view refreshes, while method B suffers from an async hop i.e the observation event happens _after_ the 'after changes' SwiftUI snapshot. It misses SwiftUI's deadline for changes in the current transaction. It's also for this reason that an asynchronous sequence based API wouldn't help us here either.

To make this work how we want it, we really need Observable to generate trailing edge (`didSet`) _synchronous_ notifications.

This would allow dependent observers to make any changes they need to make within SwiftUI's deadline for the current event loop.

It doesn't need to be anything huge for this version of the proposal, something as simple as changing `withObservationTracking(_:onChange:)` to `withObservationTracking(_:willChange:didChange:)` could lay the foundation.

---

_[View the full topic](https://forums.swift.org/t/accepted-with-revision-se-0395-observability/66760)._
