# Extend Property Wrappers to Function Arguments and Closure Parameters

**URL:** <https://forums.swift.org/t/extend-property-wrappers-to-function-arguments-and-closure-parameters/38523>\
**Category:** Discussion\
**Created:** [July 17, 2020, 12:19pm UTC](https://forums.swift.org/t/extend-property-wrappers-to-function-arguments-and-closure-parameters/38523 "2020-07-17T12:19:09Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![filip-sakel](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/filip-sakel/32/8697_2.png) [@filip-sakel](https://forums.swift.org/u/filip-sakel)\
**Post date:** [July 17, 2020, 12:19pm UTC](https://forums.swift.org/t/extend-property-wrappers-to-function-arguments-and-closure-parameters/38523/1 "2020-07-17T12:19:09Z")

</div>

> **Warning**
>
> This proposal assumes that [this proposal](https://forums.swift.org/t/proposal-allow-property-wrappers-with-multiple-arguments-to-defer-initialization-when-wrappedvalue-is-not-specified/38319) 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:

```swift
// 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:

```swift
// 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)

```swift
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:

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

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

```

Of course, there are more complex cases:

```swift
@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:

```swift
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?

```swift
@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`:

```swift
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:

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

```

is transformed into this:

```swift
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

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

```

Becomes:

```swift
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

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

```

Becomes:

```swift
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

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

```

Becomes:

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

    ...
}

```

#### Wrapped-value-type initializers

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

```

Becomes:

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

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

```

#### Complex cases

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

```

Becomes:

```swift
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`

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

```

Becomes:

```swift
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
    ))
}

```

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [July 17, 2020, 2:39pm UTC](https://forums.swift.org/t/extend-property-wrappers-to-function-arguments-and-closure-parameters/38523/2 "2020-07-17T14:39:48Z")

</div>

`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`:

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

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

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

```
