I'm reading the official Swift Programming Language Documentation and writing the code snippet examples in Playgrounds. Currently, I'm on Function Types as Return Types which seemed pretty straightforward. I'm using Xcode 16.2
The following code snippet copied from the Function Types as Return Types section is as follows:
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
However, the following error is seen for the ternary operator for stepBackward (and stepForward): "Type of expression is ambiguous without a type annotation."
This is a clean Playgrounds workspace with the default Hello World removed to verify the behavior.
I'm able to fix this by writing explicit type annotation as follows:
let forwardFunc: (Int) -> Int = stepForward
let backwardFunc: (Int) -> Int = stepBackward
@MainActor func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? backwardFunc : forwardFunc
}
This is to my understanding a good practice, but the documentation in the Functions section does not make clear this would be required.
Did something change in Swift recently that would make the documentation out of date? Is writing an explicit type annotation in these cases required now? I would like to understand why in this context the type annotation is now required, in particular with this ternary operator using inferred function types.
The following answer summarizes some of the discussion found on the Swift Forum.
This issue arose with Swift 6 and is caused by the fact that the sendForward
and sendBackward
functions are implicitly marked as @Sendable
.
The issue is resolved by updating the code from:
@MainActor func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? backwardFunc : forwardFunc
}
to:
@MainActor func chooseStepFunction(backward: Bool) -> @Sendable (Int) -> Int {
return backward ? backwardFunc : forwardFunc
}
Note the addition of @Sendable
for the function's return type.
Another workaround is to split the return
line:
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
let sendableFunc = backward ? stepBackward : stepForward
return sendableFunc // casts `@Sendable (Int)->Int` to `(Int) -> Int`
}