Skip to content

Commit a2f4786

Browse files
committed
[SE-0258] Rename 'value' to 'wrappedValue'.
1 parent 1b522ba commit a2f4786

File tree

1 file changed

+46
-45
lines changed

1 file changed

+46
-45
lines changed

proposals/0258-property-wrappers.md

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ enum Lazy<Value> {
109109
self = .uninitialized(initialValue)
110110
}
111111

112-
var value: Value {
112+
var wrappedValue: Value {
113113
mutating get {
114114
switch self {
115115
case .uninitialized(let initializer):
@@ -128,7 +128,7 @@ enum Lazy<Value> {
128128
```
129129

130130
A property wrapper type provides the storage for a property that
131-
uses it as a wrapper. The `value` property of the wrapper type
131+
uses it as a wrapper. The `wrappedValue` property of the wrapper type
132132
provides the actual
133133
implementation of the wrapper, while the (optional)
134134
`init(initialValue:)` enables initialization of the storage from a
@@ -173,7 +173,7 @@ struct UserDefault<T> {
173173
let key: String
174174
let defaultValue: T
175175

176-
var value: T {
176+
var wrappedValue: T {
177177
get {
178178
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
179179
}
@@ -213,7 +213,7 @@ implement both a mutable variant, which allows for reassignment like a
213213
struct DelayedMutable<Value> {
214214
private var _value: Value? = nil
215215

216-
var value: Value {
216+
var wrappedValue: Value {
217217
get {
218218
guard let value = _value else {
219219
fatalError("property accessed before being initialized")
@@ -240,7 +240,7 @@ a `let`:
240240
struct DelayedImmutable<Value> {
241241
private var _value: Value? = nil
242242

243-
var value: Value {
243+
var wrappedValue: Value {
244244
get {
245245
guard let value = _value else {
246246
fatalError("property accessed before being initialized")
@@ -297,7 +297,7 @@ struct Copying<Value: NSCopying> {
297297
self._value = value.copy() as! Value
298298
}
299299

300-
var value: Value {
300+
var wrappedValue: Value {
301301
get { return _value }
302302
set {
303303
// Copy the value on reassignment.
@@ -324,7 +324,7 @@ struct Atomic<Value> {
324324
self._value = initialValue
325325
}
326326

327-
var value: Value {
327+
var wrappedValue: Value {
328328
get { return load() }
329329
set { store(newValue: newValue) }
330330
}
@@ -406,7 +406,7 @@ final class ThreadSpecific<T> {
406406
}
407407
}
408408

409-
var value: T {
409+
var wrappedValue: T {
410410
get { return box.pointee as! T }
411411
set (v) {
412412
box.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee = v }
@@ -427,20 +427,20 @@ protocol Copyable: AnyObject {
427427
@propertyWrapper
428428
struct CopyOnWrite<Value: Copyable> {
429429
init(initialValue: Value) {
430-
value = initialValue
430+
wrappedValue = initialValue
431431
}
432432

433-
private(set) var value: Value
433+
private(set) var wrappedValue: Value
434434

435435
var wrapperValue: Value {
436436
mutating get {
437-
if !isKnownUniquelyReferenced(&value) {
438-
value = value.copy()
437+
if !isKnownUniquelyReferenced(&wrappedValue) {
438+
wrappedValue = value.copy()
439439
}
440-
return value
440+
return wrappedValue
441441
}
442442
set {
443-
value = newValue
443+
wrappedValue = newValue
444444
}
445445
}
446446
}
@@ -470,7 +470,7 @@ struct Ref<Value> {
470470
let read: () -> Value
471471
let write: (Value) -> Void
472472

473-
var value: Value {
473+
var wrappedValue: Value {
474474
get { return read() }
475475
nonmutating set { write(newValue) }
476476
}
@@ -503,7 +503,7 @@ write out the getters and setters, and it's fairly common to have a `Box` type t
503503
```swift
504504
@propertyWrapper
505505
class Box<Value> {
506-
var value: Value
506+
var wrappedValue: Value
507507

508508
init(initialValue: Value) {
509509
self.value = initialValue
@@ -537,7 +537,7 @@ There are a number of existing types that already provide the basic structure of
537537
struct UnsafeMutablePointer<Pointee> {
538538
var pointee: Pointee { ... }
539539

540-
var value: Pointee {
540+
var wrappedValue: Pointee {
541541
get { return pointee }
542542
set { pointee = newValue }
543543
}
@@ -556,7 +556,7 @@ print(someInt)
556556
$someInt.deallocate()
557557
```
558558

559-
RxCocoa's [`BehaviorRelay`](https://github.com/ReactiveX/RxSwift/blob/master/RxCocoa/Traits/BehaviorRelay.swift) replays the most recent value provided to it for each of the subscribed observers. It is created with an initial value, has `value` property to access the current value, as well as API to `subscribe` a new observer: (Thanks to Adrian Zubarev for pointing this out)
559+
RxCocoa's [`BehaviorRelay`](https://github.com/ReactiveX/RxSwift/blob/master/RxCocoa/Traits/BehaviorRelay.swift) replays the most recent value provided to it for each of the subscribed observers. It is created with an initial value, has `wrappedValue` property to access the current value, as well as API to `subscribe` a new observer: (Thanks to Adrian Zubarev for pointing this out)
560560

561561
```swift
562562
@BehaviorRelay
@@ -579,7 +579,7 @@ the wrappers are composed together to get both effects. For example, consider th
579579

580580
Here, we have a property for which we can delay initialization until later. When we do set a value, it will be copied via `NSCopying`'s `copy` method.
581581

582-
Composition is implemented by nesting later wrapper types inside earlier wrapper types, where the innermost nested type is the original property's type. For the example above, the backing storage will be of type `DelayedMutable<Copying<UIBezierPath>>`, and the synthesized getter/setter for `path` will look through both levels of `.value`:
582+
Composition is implemented by nesting later wrapper types inside earlier wrapper types, where the innermost nested type is the original property's type. For the example above, the backing storage will be of type `DelayedMutable<Copying<UIBezierPath>>`, and the synthesized getter/setter for `path` will look through both levels of `.wrappedValue`:
583583

584584
```swift
585585
var $path: DelayedMutable<Copying<UIBezierPath>> = .init()
@@ -610,7 +610,7 @@ type:
610610
`@propertyWrapper`. The attribute indicates that the type is meant to
611611
be used as a property wrapper type, and provides a point at which the
612612
compiler can verify any other consistency rules.
613-
2. The property wrapper type must have a property named `value`, whose
613+
2. The property wrapper type must have a property named `wrappedValue`, whose
614614
access level is the same as that of the type itself. This is the
615615
property used by the compiler to access the underlying value on the
616616
wrapper instance.
@@ -625,7 +625,7 @@ in one of three ways:
625625
1. Via a value of the original property's type (e.g., `Int` in `@Lazy var
626626
foo: Int`, using the the property wrapper type's
627627
`init(initialValue:)` initializer. That initializer must have a single
628-
parameter of the same type as the `value` property (or
628+
parameter of the same type as the `wrappedValue` property (or
629629
be an `@autoclosure` thereof) and have the same access level as the
630630
property wrapper type itself. When `init(initialValue:)` is present,
631631
is is always used for the initial value provided on the property
@@ -708,30 +708,30 @@ If the first property wrapper type is generic, its generic arguments must either
708708
// infers the type of `$someInt` to be `UnsafeMutablePointer<Int>`
709709
```
710710

711-
* Otherwise, if there is no initialization, and the original property has a type annotation, the type of the `value` property in the last wrapper type is constrained to equal the type annotation of the original property. For example:
711+
* Otherwise, if there is no initialization, and the original property has a type annotation, the type of the `wrappedValue` property in the last wrapper type is constrained to equal the type annotation of the original property. For example:
712712

713713
```swift
714714
@propertyWrapper
715715
struct Function<T, U> {
716-
var value: (T) -> U? { ... }
716+
var wrappedValue: (T) -> U? { ... }
717717
}
718718

719719
@Function var f: (Int) -> Float? // infers T=Int, U=Float
720720
```
721721

722-
In any case, the first wrapper type is constrained to be a specialization of the first attribute's written type. Furthermore, for any secondary wrapper attributes, the type of the value property of the previous wrapper type is constrained to be a specialization of the attribute's written type. Finally, if a type annotation is given, the type of the value property of the last wrapper type is constrained to equal the type annotation. If these rules fail to deduce all the type arguments for the first wrapper type, or if they are inconsistent with each other, the variable is ill-formed. For example:
722+
In any case, the first wrapper type is constrained to be a specialization of the first attribute's written type. Furthermore, for any secondary wrapper attributes, the type of the wrappedValue property of the previous wrapper type is constrained to be a specialization of the attribute's written type. Finally, if a type annotation is given, the type of the wrappedValue property of the last wrapper type is constrained to equal the type annotation. If these rules fail to deduce all the type arguments for the first wrapper type, or if they are inconsistent with each other, the variable is ill-formed. For example:
723723

724724
```swift
725725
@Lazy<Int> var foo: Int // okay
726-
@Lazy<Int> var bar: Double // error: Lazy<Int>.value is of type Int, not Double
726+
@Lazy<Int> var bar: Double // error: Lazy<Int>.wrappedValue is of type Int, not Double
727727
```
728728

729729
The deduction can also provide a type for the original property (if a type annotation was omitted) or deduce generic arguments that have omitted from the type annotation. For example:
730730

731731
```swift
732732
@propertyWrapper
733733
struct StringDictionary {
734-
var value: [String: String]
734+
var wrappedValue: [String: String]
735735
}
736736

737737
@StringDictionary var d1. // infers Dictionary<String, String>
@@ -759,30 +759,30 @@ This formulation of custom attributes fits in with a [larger proposal for custom
759759

760760
### Mutability of properties with wrappers
761761

762-
Generally, a property that has a property wrapper will have both a getter and a setter. However, the setter may be missing if the `value` property of the property wrapper type lacks a setter, or its setter is inaccessible.
762+
Generally, a property that has a property wrapper will have both a getter and a setter. However, the setter may be missing if the `wrappedValue` property of the property wrapper type lacks a setter, or its setter is inaccessible.
763763

764-
The synthesized getter will be `mutating` if the property wrapper type's `value` property is `mutating` and the property is part of a `struct`. Similarly, the synthesized setter will be `nonmutating` if either the property wrapper type's `value` property has a `nonmutating` setter or the property wrapper type is a `class`. For example:
764+
The synthesized getter will be `mutating` if the property wrapper type's `wrappedValue` property is `mutating` and the property is part of a `struct`. Similarly, the synthesized setter will be `nonmutating` if either the property wrapper type's `wrappedValue` property has a `nonmutating` setter or the property wrapper type is a `class`. For example:
765765

766766
```swift
767767
@propertyWrapper
768768
struct MutatingGetterWrapper<Value> {
769-
var value: Value {
769+
var wrappedValue: Value {
770770
mutating get { ... }
771771
set { ... }
772772
}
773773
}
774774

775775
@propertyWrapper
776776
struct NonmutatingSetterWrapper<Value> {
777-
var value: Value {
777+
var wrappedValue: Value {
778778
get { ... }
779779
nonmutating set { ... }
780780
}
781781
}
782782

783783
@propertyWrapper
784784
class ReferenceWrapper<Value> {
785-
var value: Value
785+
var wrappedValue: Value
786786
}
787787

788788
struct Usewrappers {
@@ -897,7 +897,7 @@ let $y = 17 // error: cannot declare entity with $-prefixed name '$y'
897897

898898
### Delegating access to the storage property
899899

900-
A property wrapper type can choose to hide its instance entirely by providing a property named `wrapperValue`. As with the `value` property and`init(initialValue:)`, the `wrapperValue` property must have the
900+
A property wrapper type can choose to hide its instance entirely by providing a property named `wrapperValue`. As with the `wrappedValue` property and`init(initialValue:)`, the `wrapperValue` property must have the
901901
same access level as its property wrapper type. When present, the synthesized storage property is hidden completely and the property `$foo` becomes a computed property accessing the storage property's `wrapperValue`. For example:
902902

903903
```swift
@@ -914,7 +914,7 @@ struct LongTermStorage<Value> {
914914
pointer.initialize(to: initialValue)
915915
}
916916

917-
var value: Value {
917+
var wrappedValue: Value {
918918
get { return pointer.pointee }
919919
set { pointer.pointee = newValue }
920920
}
@@ -954,7 +954,7 @@ struct ArenaStorage<Value> {
954954
pointer.initialize(to: initialValue)
955955
}
956956

957-
var value: Value {
957+
var wrappedValue: Value {
958958
get { return pointer.pointee }
959959
set { pointer.pointee = newValue }
960960
}
@@ -986,7 +986,7 @@ There are a number of restrictions on the use of property wrappers when defining
986986
* A property with a wrapper cannot be `lazy`, `@NSCopying`, `@NSManaged`, `weak`, or `unowned`.
987987
* A property with a wrapper must be the only property declared within its enclosing declaration (e.g., `@Lazy var (x, y) = /* ... */` is ill-formed).
988988
* A property with a wrapper shall not define a getter or setter.
989-
* The `value` property and (if present) `init(initialValue:)` of a property wrapper type shall have the same access as the property wrapper type.
989+
* The `wrappedValue` property and (if present) `init(initialValue:)` of a property wrapper type shall have the same access as the property wrapper type.
990990
* The `wrapperValue` property, if present, shall have the same access as the property wrapper type.
991991
* The `init()` initializer, if present, shall have the same access as the property wrapper type.
992992

@@ -1019,7 +1019,7 @@ Composition was left out of the [first revision](https://github.com/apple/swift-
10191019
struct AB<Value> {
10201020
private var storage: A<B<Value>>
10211021

1022-
var value: Value {
1022+
var wrappedValue: Value {
10231023
get { storage.value.value }
10241024
set { storage.value.value = newValue }
10251025
}
@@ -1034,7 +1034,7 @@ One proposed approach to composition addresses only the last issue above directl
10341034
```swift
10351035
@propertyWrapper
10361036
struct A<Value> {
1037-
var value: Value { ... }
1037+
var wrappedValue: Value { ... }
10381038
}
10391039

10401040
extension A {
@@ -1054,7 +1054,7 @@ There has been a desire to effect composition of property wrappers without havin
10541054
@A @B var x: Int
10551055
```
10561056

1057-
the `Int` value is conceptually wrapped by a property wrapper type, and the property wrapper type's `value` property guards access to that (conceptual) `Int` value. That `Int` value cannot be wrapped both by instances of both `A` and `B` without either duplicating data (both `A` and `B` have a copy of the `Int`) or nesting one of the wrappers inside the other. With the copying approach, one must maintain consistency between the copies (which is particularly hard when value types are involved) and there will still be non-commutative compositions. Nesting fits better with the "wrapper" model of property wrappers.
1057+
the `Int` value is conceptually wrapped by a property wrapper type, and the property wrapper type's `wrappedValue` property guards access to that (conceptual) `Int` value. That `Int` value cannot be wrapped both by instances of both `A` and `B` without either duplicating data (both `A` and `B` have a copy of the `Int`) or nesting one of the wrappers inside the other. With the copying approach, one must maintain consistency between the copies (which is particularly hard when value types are involved) and there will still be non-commutative compositions. Nesting fits better with the "wrapper" model of property wrappers.
10581058

10591059
### Using a formal protocol instead of `@propertyWrapper`
10601060

@@ -1065,12 +1065,12 @@ types. It might look like this:
10651065
```swift
10661066
protocol PropertyWrapper {
10671067
associatedtype Value
1068-
var value: Value { get }
1068+
var wrappedValue: Value { get }
10691069
}
10701070
```
10711071

10721072
There are a few issues here. First, a single protocol
1073-
`PropertyWrapper` cannot handle all of the variants of `value` that
1073+
`PropertyWrapper` cannot handle all of the variants of `wrappedValue` that
10741074
are implied by the section on mutability of properties with wrappers,
10751075
because we'd need to cope with `mutating get` as well as `set` and
10761076
`nonmutating set`. Moreover, protocols don't support optional
@@ -1152,7 +1152,7 @@ One could also consider having the property wrapper types themselves declare tha
11521152
```swift
11531153
@propertyWrapper(wrapperIsAccessible: true)
11541154
struct Atomic<T> {
1155-
var value: T { ... }
1155+
var wrappedValue: T { ... }
11561156
}
11571157

11581158
// both bar and $bar are publicly visible
@@ -1201,7 +1201,7 @@ public struct Observable<Value> {
12011201
self.observed = observed
12021202
}
12031203

1204-
public var value: Value {
1204+
public var wrappedValue: Value {
12051205
get { return stored }
12061206
set {
12071207
if newValue != stored {
@@ -1229,7 +1229,7 @@ public class MyClass: Superclass {
12291229

12301230
This isn't as automatic as we would like, and it requires us to have a separate reference to the `self` that is stored within `Observable`.
12311231

1232-
Instead, we could extend the ad hoc protocol used to access the storage property of a `@propertyWrapper` type a bit further. Instead of (or in addition to) a `value` property, a property wrapper type could provide a `subscript(instanceSelf:)` and/or `subscript(typeSelf:)` that receive `self` as a parameter. For example:
1232+
Instead, we could extend the ad hoc protocol used to access the storage property of a `@propertyWrapper` type a bit further. Instead of (or in addition to) a `wrappedValue` property, a property wrapper type could provide a `subscript(instanceSelf:)` and/or `subscript(typeSelf:)` that receive `self` as a parameter. For example:
12331233

12341234

12351235
```swift
@@ -1272,7 +1272,7 @@ This change is backward-compatible with the rest of the proposal. Property wrapp
12721272

12731273
* For instance properties, `subscript(instanceSelf:)` as shown above.
12741274
* For static or class properties, `subscript(typeSelf:)`, similar to the above but accepting a metatype parameter.
1275-
* For global/local properties, or when the appropriate `subscript` mentioned above isn't provided by the wrapper type, the `value` property would be used.
1275+
* For global/local properties, or when the appropriate `subscript` mentioned above isn't provided by the wrapper type, the `wrappedValue` property would be used.
12761276

12771277
The main challenge with this design is that it doesn't directly work when the enclosing type is a value type and the property is settable. In such cases, the parameter to the subscript would get a copy of the entire enclosing value, which would not allow mutation, On the other hand, one could try to pass `self` as `inout`, e.g.,
12781278

@@ -1314,7 +1314,8 @@ One could express this either by naming the property directly (as above) or, for
13141314
* Reduced the visibility of the synthesized storage property to `private`, and expanded upon potential future directions to making it more visible.
13151315
* Removed the restriction banning property wrappers from having names that match the regular expression `_*[a-z].*`.
13161316
* `Codable`, `Hashable`, and `Equatable` synthesis are now based on the backing storage properties, which is a simpler model that gives more control to the authors of property wrapper types.
1317-
* Improved type inference for property wrapper types and clarified that the type of the `value` property is used as part of this inference. See the "Type inference" section.
1317+
* Improved type inference for property wrapper types and clarified that the type of the `wrappedValue` property is used as part of this inference. See the "Type inference" section.
1318+
* Renamed the `value` property to `wrappedValue` to avoid conflicts.
13181319

13191320
## Acknowledgments
13201321

0 commit comments

Comments
 (0)