Skip to content

Commit 77f9c33

Browse files
authored
[Proposal] ProgressManager Post-Review Update (#1519)
* add alternatives considered * address PR comments * refine Property protocol alternatives considered * refine withProperties alternatives considered * refine withProperties alternatives considered * more detail for alternatives considerd * edit proposal revision history * edit alternatives considered * fix typo * fix alternatives considered
1 parent abfcc28 commit 77f9c33

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

Proposals/0023-progress-manager.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,9 @@
4242
- Expanded Alternatives Considered
4343
* **v6** Minor Updates:
4444
- Replaced `withProperties` method with `setCounts`
45-
- Removed `ProgressManager.Values` struct
46-
- Made `ProgressManager` conform to `@dynamicMemberLookup` and moved `subscript(dynamicMember:)` methods from `ProgressManager.Values` to `ProgressManager`
45+
- Moved `@dynamicMemberLookup` attribute to `ProgressManager` and `ProgressReporter`
4746
- Changed behavior of API so that additional properties are restricted to either `Int`, `Double`, `String?`, `URL?`, `UInt64` or `Duration` types instead of `any Sendable` types
48-
- Added overloads for `subscript(dynamicMember:)` to account for currently-allowed types
49-
- Added requirements to `ProgressManager.Property` protocol to define summarization and termination (deinit) behavior
47+
- Added requirements to `ProgressManager.Property` protocol to define summarization and cleanup (deinit) behavior
5048
- Replaced `total(of:)` with overloads for `summary(of:)` to account for all available types and removed `values(of:)` method
5149

5250
## Table of Contents
@@ -1434,6 +1432,31 @@ There were discussions about representing indeterminate state in `ProgressManage
14341432
### Allow declared custom additional property to be any type that can be casted as `any Sendable`
14351433
We initially allowed the full flexibility of allowing developers to declare `ProgressManager.Property` types to be of any type, including structs. However, we realized that this has a severely negative impact on performance of the API. Thus, for now, we allow developers to only declare `ProgressManager.Property` with only certain `Value` and `Summary` types.
14361434

1435+
### Use `withProperties` closure as entry point to mutate custom `ProgressManager.Property` types
1436+
We initially introduced the `withProperties` closure to mutate custom `ProgressManager.Property` types. However, with the use of `withProperties` closure and the need to make custom `ProgressManager.Property` types [`Observable`](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0395-observability.md), we needed to register all the updates of each custom property on one keypath. This is to ensure that `ObservationRegistrar`'s `access` and `withMutation` calls are not called from within a locked context. Registering all updates of custom properties on one keypath can cause unnecessary UI redraws, which negatively impacts performance. Therefore, we decided to move the `@dynamicMemberLookup` attribute to `ProgressManager` to allow each custom `ProgressManager.Property` to be individually `Observable`. Additionally, this allows developers to access custom `ProgressManager.Property` types via dot syntax, improving the discoverability and ergonomics of accessing and mutating custom `ProgressManager.Property` types. The `withProperties` closure is replaced with `setCounts` to preserve the same atomic behavior for mutations of `totalCount` and `completedCount`.
1437+
1438+
### Minimal requirements for `ProgressManager.Property` protocol
1439+
We initially considered a version of the `ProgressManager.Property` protocol that only had two requirements:
1440+
1441+
- `Value` - The type for individual property values
1442+
- `defaultValue` - A default value when the property isn't explicitly set
1443+
1444+
In this approach, the `ProgressManager` API handles custom `ProgressManager.Property` types by:
1445+
- Aggregating all values throughout a progress tree into `Array<Value>`
1446+
- Providing access via `values(of:)` method returning arrays of individual values
1447+
- Providing access via `total(of:)` method returning computed summaries (e.g., `Int` for `totalFileCount`)
1448+
- Deciding whether values are dropped or retained when `ProgressManager` instances are deinitialized
1449+
1450+
However, after extensive performance testing, we realized that this approach for supporting arbitrary types has worse performance and offers much less flexibility for specifying the summarization behavior that developers may need.
1451+
1452+
We decided to introduce additional requirements that would yield better performance and provide more flexibility:
1453+
- `Summary` - Explicit type for summaries
1454+
- `reduce(into:value:)` - Custom logic for incorporating individual values into summaries
1455+
- `merge(_:_:)` - Custom logic for combining summaries from different `ProgressManager` instances
1456+
- `finalSummary(_:_:)` - Custom behavior when `ProgressManager` instances are deinitialized
1457+
1458+
With these additional requirements, the support for custom `ProgressManager.Property` types balances performance and flexibility.
1459+
14371460
## Acknowledgements
14381461
Thanks to
14391462
- [Tony Parker](https://github.com/parkera),

0 commit comments

Comments
 (0)