# Extend Property Wrappers to Function Arguments and Closure Parameters

Warning

This proposal assumes that this proposal has been added to the language, since this proposal is in the earliest stage of evolution and feedback for the attached proposal seems to be very positive.

### Motivation

Property wrappers are currently limited to type properties. Use in function arguments or even closures is currently not possible leading to friction in development:

``````// Use in functions as an argument
func takeBinding(count: Binding<Int>) {
count.wrappedValue = 1
//    ^~~~~~~~~~~~ Introduces friction
}

// Use as an argument passed to a closure
func closureUsingBinding(
_ block: (Binding<Int>) -> Void
) { ... }

closureUsingBinding { count in
count.wrappedValue = 2
//    ^~~~~~~~~~~~ Introduces friction
}
``````

We essentially see the problem property wrappers were introduced to solve in a slightly different form.

### Potential Solution

#### Declarations

We could enable property wrappers in the above cases:

``````// Use in functions as an argument
func takeBinding(@Binding count: Int) {
count = 1
// 🙂 Natural use
}

// Use as an argument passed to a closure
closureUsingBinding { @Binding count in
count.wrappedValue = 2
// 🙂 Natural use
}
``````

#### Calling such functions (and closures)

``````takeBinding(count: \$count)

func closureUsingBinding(
_ block: (Binding<Int>) -> Void
) {
block(\$myCountBinding)
}
``````

Some property wrappers however provide wrapped-property-style initializers: `init(wrappedValue:)`. For such initializers convenience functions would be created:

``````func takeState(@State count: Int = 0) { ... }

takeState()
takeState(count: 1)
takeState(count: State(
wrappedValue: 2
))
``````

Of course, there are more complex cases:

``````@propertyWrapper
struct Wrapper<Value> {
...

init(foo: String, wrappedValue value: Value) {
...
}
}

func takeWrapper(
@Wrapper(foo: "bar") wrapper: Int = 0
) { ... }

// Calling `takeWrapper`

takeWrapper()
takeWrapper(wrapper: 1)
takeWrapper(wrapper: Wrapper(
foo: "bar",
wrappedValue: 2
))
``````

But sometimes it makes sense for the `wrappedValue` not to be automatically provided:

``````func takeWrapper(
@Wrapper(foo: "bar") wrapper: Int
) { ... }

// Calling `takeWrapper`

takeWrapper(wrapper: 1) // `wrapper` is required
takeWrapper(wrapper: Wrapper(
foo: "bar",
wrappedValue: 2
))
``````

#### How would this work with mutable property wrappers?

``````@propertyWrapper
struct Mutable<Value> {
var wrappedValue: Value
}

func takeMutable(@Mutable count: inout Int) {
//                           ^~~~~
// ✅ Allowed, since count is inout

...
}

func takeMutable(@Mutable count: Int) {
//                          ^~~~
// ❌ `Mutable` requires that
//  count be marked inout.

...
}
``````

Note that property wrappers like `State` will work without being mark `inout`:

``````func takeState(@State count: Int) { ... }
``````

That behavior is intentional as `State` is actually not mutable. In fact, it's `wrappedValue` property is marked `get` and `nonmutating set`.

### Transformations

As in the original proposal the compiler magic lies in the transformations. Currently, this:

``````struct Foo {
@Mutable var bar: Int
}
``````

is transformed into this:

``````struct Foo {
var _bar: Mutable<Int>

var bar: Int {
get {
_bar.wrappedValue
}
set {
_bar.wrappedValue = newValue
}
}
}
``````

Likewise, transformation would also occur with this solution:

#### Simple case

``````func takeBinding(@Binding count: Int) {
...
}
``````

Becomes:

``````func takeBinding(count _count: Binding<Int>) {
var count: Int {
get {
_count.wrappedValue
}
nonmutating set {
_count.wrappedValue = newValue
}
}

var \$count: Binding<Int> {
_count.projectedValue
}

...
}
``````

#### Custom labels

``````func increment(@Binding by count: Int) {
...
}
``````

Becomes:

``````func takeBinding(by _count: Binding<Int>) {
var count: Int { ... }

var \$count: Binding<Int> { ... }

...
}
``````

#### So what's the behavior with labels?

The label written out by the user becomes the custom label and the property name is prefixed with "_".

#### Closure arguments

``````closureUsingBinding { @Binding count in
...
}
``````

Becomes:

``````closureUsingBinding { (_count: Binding<Int>) -> Void in
var count: Int { ... }

var \$count: Binding<Int> { ... }

...
}
``````

#### Wrapped-value-type initializers

``````func takeState(
@State count: Int = 0
) { ... }
``````

Becomes:

``````func takeState(
count _count: State<Int>
) {
...
}

// Synthesized function
func takeState(
count: Int = 0
) {
takeState(count: State<Int>(
wrappedValue: count
))
}
``````

#### Complex cases

``````func takeWrapper(
@Wrapper(foo: "bar") wrapper: Int = 0
) { ... }
``````

Becomes:

``````func takeWrapper(
wrapper _wrapper: Wrapper<Int>
) {
var wrapper: Int { ... }

...
}

// Synthesized function
func takeWrapper(
wrapper: Int = 0
) {
takeWrapper(Wrapper<Int>(
foo: "bar",
wrappedValue: wrapper
))
}
``````

#### Complex cases with no provided `wrappedValue`

``````func takeWrapper(
@Wrapper(foo: "bar") wrapper: Int
) { ... }
``````

Becomes:

``````func takeWrapper(
wrapper _wrapper: Wrapper<Int>
) {
...
}

// Synthesized function
func takeWrapper(
wrapper: Int // There is no `= 0` here,
// so specifying `wrapper`
// is mandatory
) {
takeWrapper(Wrapper<Int>(
foo: "bar",
wrappedValue: wrapper
))
}
``````

`Binding` is a poor motivation for this feature. Most of the time you only mutate the wrapped value, and not the binding itself. So forcing the caller to use `Binding` is unnecessarily restrictive when you can just normally use `inout`, which already works with `Binding`:

``````struct Foo {
@Binding var value: Bool
init() { _value = .constant(false) }
}

func mutate(_: inout Bool) { ... }

let foo = Foo()
mutate(&foo.value) // ok
``````