[Pitch #3] Property wrappers (formerly known as Property Delegates)

I have the following trivial example to show composition:

struct Adjusting<V> {
    var value: V {
        didSet { value = transform(value) }
    }

    private var transform: (V) -> (V)

    init(initialValue: V, _ transform: @escaping (V) -> (V)) {
        self.value = initialValue
        self.transform = transform
    }
}

@_propertyDelegate
struct Clamping<V: Comparable> {
    @Adjusting var value: V

    init(initialValue: V, min minimum: V, max maximum: V) {
        $value = Adjusting(initialValue: initialValue,
                           { max(min($0, maximum), minimum) })
    }
}

@_propertyDelegate
struct Min<V: FixedWidthInteger> {
    @Clamping var value: V

    init(initialValue: V, min minimum: V) {
        $value = Clamping(initialValue: initialValue,
                          min: minimum, max: V.self.max)
    }
}

@_propertyDelegate
struct Max<V: FixedWidthInteger> {
    @Clamping var value: V

    init(initialValue: V, max maximum: V) {
        $value = Clamping(initialValue: initialValue,
                          min: V.self.min, max: maximum)
    }
}

class C {
    @Adjusting(initialValue: 0, { max(0, $0) }) var a: Int
    @Clamping(initialValue: 1, min: 1, max: 7) var b: Int
    @Min(initialValue: 0, min: 7) var c: Int
}

Is there any way to change the syntax so that it's not necessary to provide an initialValue to the constructors? I'd much rather see something like this:

@Clamping(min: 1, max: 7) var a = 13 

rewritten by the compiler as

let $a = Clamping(initialValue: 13, min: 1, max: 7)
var a: Int {
    get { $a.value }
    set { $a.value = newValue }
}

Essentially extend the current logic which looks for init(initialValue: T) to also look for init(initialValue: T, ... <other args from declaration>)

6 Likes