struct TwelveOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
struct SmallRectangle {
@TwelveOrLess var height: Int
@TwelveOrLess var width: Int
}
...and its “unfolded” form...
struct SmallRectangle {
private var _height = TwelveOrLess()
private var _width = TwelveOrLess()
var height: Int {
get { return _height.wrappedValue }
set { _height.wrappedValue = newValue }
}
var width: Int {
get { return _width.wrappedValue }
set { _width.wrappedValue = newValue }
}
}
...the necessary functionality is both of these:
var rectangle = SmallRectangle()
rectangle.height = 10 // ← Assigned a new value to the same wrapper.
rectangle._height = TwelveOrLess() // ← Overwrote the wrapper itself.
Is there some way of making the same functionality available while still using the property wrapper form? (In the actual use case, the wrapper must be a class, so assigning self is problematic.)
@propertyWrapper
class TwelveOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
struct SmallRectangle {
@TwelveOrLess var height: Int
@TwelveOrLess var width: Int
mutating func update() {
height = 10
_height = TwelveOrLess()
}
}
Interesting. I didn’t realize the low‐lined variants actually existed. Do they carry a guarantee of stability, or are they just a leaked implementation detail?
Regardless, when I try that I get:
'_property' is inaccessible due to 'private' protection level
It needs to be possible at the public level.
I haven’t tried it yet, but I have a hunch I can make it work by nesting things differently. If it works, I’ll post the code.
It worked. I rearranged the code by adding an additional type for nesting:
public class TwelveOrLess {
// Note that we are dealing with a class, not a structure.
// This type is no longer technically a property wrapper itself,
// but it still does all the work and handles the storage.
private var number = 0
public var value: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
@propertyWrapper public struct TwelveOrLessProperty {
public var projectedValue: TwelveOrLess
public var wrappedValue: Int {
get { return projectedValue.value }
set { projectedValue.value = newValue }
}
}
public struct SmallRectangle {
@TwelveOrLessProperty public var height: Int
@TwelveOrLessProperty public var width: Int
}
var rectangle = SmallRectangle()
rectangle.height = 10 // ← Assigned a new value to the same pseudo‐wrapper.
rectangle.$height = TwelveOrLess() // ← Overwrote the pseudo‐wrapper itself.
It's worth noting for anyone else who happens across this thread that if the wrapper were not required to be a class, you'd be able to do this without the extra indirection:
@propertyWrapper
struct TwelveOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
var projectedValue: Self {
get { return self }
set { self = newValue }
}
}
struct SmallRectangle {
@TwelveOrLess var height: Int
@TwelveOrLess var width: Int
}
var rectangle = SmallRectangle()
rectangle.height = 10 // ← Assigned a new value to the same wrapper.
rectangle.$height = TwelveOrLess() // ← Overwrote the wrapper itself.
But Jeremy set the requirement that it be a class up front, so the extra level of nesting is probably the best answer.