I'm trying to implement a convenience Collection.sorted(by: KeyPath)
function.
So far, it works if do
func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>) -> [Element] {
return sorted { lhs, rhs
return lhs[keyPath: keyPath] < rhs[keyPath: keyPath]
}
}
But what if I want to allow the caller to specify the actual sorting logic ? I added a callback to perform the comparison, like such (taking inspiration from the orginal sorted(_:)
function signature).
func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>, _ compare: (T, T) throws -> Bool) rethrows -> [Element] {
return try sorted { lhs, rhs in
return try compare(lhs[keyPath: keyPath], rhs[keyPath: keyPath])
}
}
Now, this is all works, but it means the callsite always has to specify which sorting operation to perform.
let sorted = myArray.sorted(by: \.name, <)
I'd like it to default to <
, but how can I reference the <
operator by default, in my function's signature ?
It is actually possible to reference the un-applied <
function by wrapping it in parentheses (<)
when using it as a default parameter.
func sorted<T: Comparable>(
by keyPath: KeyPath<Element, T>,
_ compare: (T, T) throws -> Bool = (<)
) rethrows -> [Element] {
return try sorted { lhs, rhs in
return try compare(lhs[keyPath: keyPath], rhs[keyPath: keyPath])
}
}
However, there is currently an issue with the compiler when doing this.
Even though <
doesn't throw, the compiler will still enforce you to use try
at the call site.
A bug report for this was opened quite some time ago, and is still unresolved. If you run into this, please upvote it: https://bugs.swift.org/browse/SR-1534
Additionally, as pointed out in the comments, the sorted(by:)
function is actually 2 different functions.
One requires Comparable
and uses <
internally, while the other lets you specify the sorting logic directly and thus, does not require Comparable
conformance.
Therefore, this convenience sorting by keyPath
would still require 2 functions.