First of all: I really like the overall proposal.
There is on thing that I find suboptimal: While the proposed solution for closures may be helpful in some situation, I think there is a much more ergonomic solution. Let me explain:
The proposal suggests that an API author would create a function that takes a closure like this:
func useValue(_ handler: (Binding<String>) -> Void) { ... }
Then let‘s suppose there are two users of this API. User A wants to access the value as well as the binding. It would look like this:
useValue { (@Binding value) in
print(value)
doSomething(binding: $value)
}
One thing bothers me in this example: Every time, user A wants to use useValue(), she has to include @Binding.
Then let‘s turn to user B. He just wants to use the plain value. However, he does not know that property wrappers can be used in closures. So he does this:
useValue { binding in
handleValue(binding.wrappedValue)
}
This does not look good to me. And even if user B would know property wrappers, he would have to include the @Binding:
useValue { (@Binding value) in
handleValue(value)
}
My solution to this problem would be the following:
The API could be written like this:
func useValue(_ handler: (@Binding String) -> Void) {
let binding: Binding<String> = getBinding()
handler(binding)
}
User A could then write this:
useValue { value in
print(value)
doSomething(binding: $value)
}
No @Binding is needed.
User B, who doesn‘t know of property wrappers would look at the API, probably google @Binding and find out about the concept. Then, he could just write:
useValue { value in
handleValue(value)
}
Or even simpler:
useValue(handleValue)
Here is another example:
let songTitles: [String] = ...
songTitles.forEach { title in
print("\($title.index): \(title)")
}
This would eliminate the need to use enumerated().
And one last example:
ForEach($entries) { entry in
HStack {
Text("\(entry):")
TextField("Entry", text: $entry)
}
}
What do you think?