Hi all,
I'm trying to use parameter packs to parameterize sorting over keypaths to comparable fields, but I'm unable to work around an error diagnostic ("type of expression is ambiguous without more context").
It's unclear to me how to say the Comparable's vary, but the T does not. Here's what I'm doing:
func less<T, C: Comparable, each E: KeyPath<T, C>> (
lhs: T, rhs: T, paths: repeat each E) -> Bool? { ... }
Same result with each C:
private static func less<T, each C: Comparable> (
lhs: T, rhs: T, paths: repeat KeyPath<T, each C>) -> Bool? { ... }
Putting the constraints in where-clause didn't help, nor did reasonable variants of ().
The code below should be complete for repro purposes.
Thoughts?
Thanks!
P.S. - fyi, the github swift Issue tracker has a label "pack expansion" which seems too narrow, but no "parameter pack" even though there are many labels found on searching "parameter".
swift-driver: 1.82.2 [...] swiftlang-5.9.0.114.6 clang-1500.0.27.1, Sonoma SDK
public struct LessDemo {
public let i: Int
public let c: Character
// Caller
public static func lessByChar(l: Self, r: Self) -> Bool {
// Be explicit about types for demonstration purposes
let sc: KeyPath<LessDemo, Character> = \LessDemo.c
let si: KeyPath<LessDemo, Int> = \LessDemo.i
// Diagnostic: type is ambiguous without more context
let b: Bool? = less(lhs: l, rhs: r, paths: sc, si)
return b ?? false
}
// Callee
private static func less<T, C: Comparable, each E: KeyPath<T, C>> (
lhs: T, rhs: T, paths: repeat each E) -> Bool? {
var result: Bool? = nil
repeat _less(result: &result, each paths, lhs: lhs, rhs: rhs)
return result
}
// Utility accepting inout to reduce result
private static func _less<T, C:Comparable, K: KeyPath<T, C>>(
result: inout Bool?, _ keyPath: KeyPath<T, C>, lhs: T, rhs: T) {
guard nil == result else { return } // short-circuit
let left = lhs[keyPath: keyPath]
let right = rhs[keyPath: keyPath]
result = left < right ? true : (left > right ? false : nil)
}
/// demo entrypoint (to build out)
public static func demo() -> String {
var many = Self.MANY
many.sort(by: Self.sortChar)
return "\(many.first ?? MANY[0])"
}
private static let KEYS
= "qwertyuiopasdfghjklzxcvbnmdupshere"
public static let MANY
= (KEYS.enumerated()).map{ Self(i: $0.0, c: $0.1) }
}