Skip to content

Commit b529ff5

Browse files
authored
Deprecate Shared's optional dynamic member lookup overload (#3145)
* Deprecate `Shared`'s optional dynamic member lookup overload Currently, `Shared`'s dynamic member lookup is overloaded for convenience: ```swift $shared // Shared<Root> $shared.value // Shared<Value> $shared.optionalValue // Shared<Value>? ``` Unfortunately, this is also perhaps surprising, and goes against the grain when folks might expect to be handed a `Shared<Value?>`. Also, there are times when you have a `Shared<Value?>` already, and you want to unwrap it. Dynamic member lookup doesn't help there (unless you know you can call `$shared[dynamicMember: \.self]`), and so you need a totally different operation to handle it: ```swift if let unwrappedShared = Shared($optional) { // Do something with 'Shared<Value>' } ``` So let's avoid this confusion in the future and focus on a single API for unwrapping shared values, which is the failable initializer that mirrors an API on `Binding`. * wip * Update SharedReader.swift * Update Shared.swift * Update SharedReader.swift
1 parent 63a0795 commit b529ff5

File tree

3 files changed

+69
-28
lines changed

3 files changed

+69
-28
lines changed

ComposableArchitecture.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/ComposableArchitecture/SharedState/Shared.swift

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ public struct Shared<Value> {
3737
}
3838

3939
public init?(_ base: Shared<Value?>) {
40-
guard let shared = base[dynamicMember: \.self] else { return nil }
41-
self = shared
40+
guard let initialValue = base.wrappedValue
41+
else { return nil }
42+
self.init(
43+
reference: base.reference,
44+
keyPath: base.keyPath.appending(path: \Value?.[default:DefaultSubscript(initialValue)])!
45+
)
4246
}
4347

4448
public var wrappedValue: Value {
@@ -117,17 +121,13 @@ public struct Shared<Value> {
117121
Shared<Member>(reference: self.reference, keyPath: self.keyPath.appending(path: keyPath)!)
118122
}
119123

124+
@available(
125+
*, deprecated, message: "Use 'Shared($value.optional)' to unwrap optional shared values"
126+
)
120127
public subscript<Member>(
121128
dynamicMember keyPath: WritableKeyPath<Value, Member?>
122129
) -> Shared<Member>? {
123-
guard let initialValue = self.wrappedValue[keyPath: keyPath]
124-
else { return nil }
125-
return Shared<Member>(
126-
reference: self.reference,
127-
keyPath: self.keyPath.appending(
128-
path: keyPath.appending(path: \.[default:DefaultSubscript(initialValue)])
129-
)!
130-
)
130+
Shared<Member>(self[dynamicMember: keyPath])
131131
}
132132

133133
public func assert(
@@ -358,16 +358,12 @@ extension Shared {
358358
SharedReader(reference: self.reference, keyPath: self.keyPath)
359359
}
360360

361+
@available(
362+
*, deprecated, message: "Use 'SharedReader($value.optional)' to unwrap optional shared values"
363+
)
361364
public subscript<Member>(
362365
dynamicMember keyPath: KeyPath<Value, Member?>
363366
) -> SharedReader<Member>? {
364-
guard let initialValue = self.wrappedValue[keyPath: keyPath]
365-
else { return nil }
366-
return SharedReader<Member>(
367-
reference: self.reference,
368-
keyPath: self.keyPath.appending(
369-
path: keyPath.appending(path: \.[default:DefaultSubscript(initialValue)])
370-
)!
371-
)
367+
SharedReader(self[dynamicMember: keyPath])
372368
}
373369
}

Sources/ComposableArchitecture/SharedState/SharedReader.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@ public struct SharedReader<Value> {
2626
}
2727

2828
public init?(_ base: SharedReader<Value?>) {
29-
guard let shared = base[dynamicMember: \.self] else { return nil }
30-
self = shared
29+
guard let initialValue = base.wrappedValue
30+
else { return nil }
31+
self.init(
32+
reference: base.reference,
33+
keyPath: base.keyPath.appending(path: \Value?.[default:DefaultSubscript(initialValue)])!
34+
)
3135
}
3236

3337
public init(_ base: Shared<Value>) {
@@ -61,17 +65,13 @@ public struct SharedReader<Value> {
6165
SharedReader<Member>(reference: self.reference, keyPath: self.keyPath.appending(path: keyPath)!)
6266
}
6367

68+
@available(
69+
*, deprecated, message: "Use 'SharedReader($value.optional)' to unwrap optional shared values"
70+
)
6471
public subscript<Member>(
6572
dynamicMember keyPath: KeyPath<Value, Member?>
6673
) -> SharedReader<Member>? {
67-
guard let initialValue = self.wrappedValue[keyPath: keyPath]
68-
else { return nil }
69-
return SharedReader<Member>(
70-
reference: self.reference,
71-
keyPath: self.keyPath.appending(
72-
path: keyPath.appending(path: \.[default:DefaultSubscript(initialValue)])
73-
)!
74-
)
74+
SharedReader<Member>(self[dynamicMember: keyPath])
7575
}
7676

7777
#if canImport(Combine)

0 commit comments

Comments
 (0)