Errors passing unapplied function references as closures

In Swift, we can normally pass a function reference as an argument to a function that expects a closure. However, in many cases that fails or produces warnings. Here are some:

Mutating function references:

let items = [1, 2, 3]
var destination: [Int] = []

// Error: Cannot reference 'mutating' method as function value
items.forEach(destination.append) 
// ok!
items.forEach { destination.append($0) }

Non-Sendable functions:

var body: some View {
  Text("Hello, World!")
    // Warning: Converting non-sendable function value to '@Sendable () async -> Void' may introduce data races
    .task(doTask) 
    // ok!
    .task { doTask() }
}

Discardable return value is not void:

@discardableResult
func log<T>(_ value: T) -> T {
    print(value)
    return value
}

// Error: Cannot convert value of type '(Void) -> Void' to expected argument type '(Int) throws -> Void'
items.forEach(log)
// ok!
items.forEach { log($0) }

Since the trivial solution of wrapping these in the most elementary closure seems to work — should we make the compiler generate the necessary thunks to do this automatically? If not, why?

I'm not sure these are problematic enough to warrant a pitch to change the lanhuage, or even needs fixing. But I'm interested in learning about the quirks of how these (and possible similar issues) surface in the language, and possible pitfalls of "fixing" them.

In the non-sendable example, I'm not even sure what is going on and why the explicit closure gets rid of the warning.

I'm not sure how to answer your questions, but I can tell that in my experience using Swift I eventually decided to discourage any usage of functions as plain values passed to other functions, and always use instead the closure approach. There are just too many things that work perfectly with explicit closures, and break when passing functions as values: the major one for me, probably, is default values, that are properly accounted for only with an explicit function call in a closure.

1 Like