Tuming
(Tuming)
October 3, 2025, 5:47am
1
I’m confused about Function Types as Return Types in TSPL.
Xcode 26.0
maxOS Tahoe 26.0
Why?
chooseStepFunction1(:) --> error
chooseStepFunction2(:) --> It works
chooseStepFunction3(:) --> It works
The TSPL doesn't explain ...
encountered chooseStepFunction1 error:
type of expression is ambiguous without a type annotation
return backward ? stepBackward : stepForward
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
// type of expression is ambiguous without a type annotation
func chooseStepFunction1(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
// works
func chooseStepFunction2(backward: Bool) -> @Sendable (Int) -> Int {
return backward ? stepBackward : stepForward
}
// works
func chooseStepFunction3(backward: Bool) -> (Int) -> Int {
if backward {
return stepForward
} else {
return stepBackward
}
}
Diggory
(Diggory)
October 3, 2025, 8:48am
2
I’m no expert, but that sounds like a bug to me.
FYI, your code compiles on Linux using Swift 5.8
ternary.swift:16:21: warning: converting non-sendable function value to '@Sendable (Int) -> Int' may introduce data races
return backward ? stepBackward : stepForward
bbrk24
October 3, 2025, 3:21pm
3
When I try this, chooseStepFunction1
compiles fine, it's chooseStepFunction2
that gives a diagnostic (for converting non-sendable (Int) -> Int
to @Sendable (Int) -> Int
). What are your build settings (e.g. do you have approachable concurrency and/or default MainActor isolation turned on? Is it Swift 5 or Swift 6? etc)
Jumhyn
(Frederick Kellison-Linn)
October 3, 2025, 4:31pm
4
chooseStepFunction1
produces an error for me in Swift 6 mode, but not Swift 5 mode.
Danny
October 3, 2025, 4:57pm
5
The errors that occur are different depending on what scope everything is defined within. For example, wrap it all in a function, and:
func f() {
func stepForward(_ input: Int) -> Int { input + 1 }
func stepBackward(_ input: Int) -> Int { input - 1 }
// Compiles.
func chooseStepFunction1(backward: Bool) -> (Int) -> Int {
backward ? stepBackward : stepForward
}
// Converting non-Sendable function value to '@Sendable (Int) -> Int' may introduce data races
func chooseStepFunction2(backward: Bool) -> @Sendable (Int) -> Int {
backward ? stepBackward : stepForward
}
}
I don't think the casting that makes everything compile should be necessary, but that's how things have been for a while.
@Sendable func stepForward(_ input: Int) -> Int { input + 1 }
@Sendable func stepBackward(_ input: Int) -> Int { input - 1 }
func chooseStepFunction1(backward: Bool) -> (Int) -> Int {
backward ? stepBackward : stepForward as (_) -> _
}
func chooseStepFunction2(backward: Bool) -> @Sendable (Int) -> Int {
backward ? stepBackward : stepForward
}