SE-0249 introduced the ability to use keypaths for a certain method signature interchangably with functions with the same signature as function arguments. So, for instance, the line `users.map( { $0.email })`

can be interchanged with the line `users.map(\.email)`

.

What I would like to propose is that, through no change to the language itself, but only some additions to the standard library, to allow keypaths to be used in certain `Sequence`

methods that accept a closure with two parameters of type `Sequence.Element`

, such as `(Element, Element) -> Bool`

as used by `Sequence.sort`

, `Sequence.min`

and `Sequence.max`

.

Such a method would allow for briefer code with less repetition for most uses of `sort/sorted`

, `min`

and `max`

, which are usually written as `sorted { $0.count < $1.count }`

or `max { $0.weight < $1.weight }`

, accessing the same property on both the left hand and right hand side of the comparison operator.

Using keypaths instead, the line `sorted { $0.count < $1.count }`

could instead be written as `sorted(by: \.count)`

, with the `sorted(by keyPath: KeyPath<Element>) -> [Element]`

method calling the current `sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element]`

method. An optional extra parameter could supply a custom `areInIncreasingOrder`

function for comparing elements.

A simplistic implementation of `sort`

, `min`

and `max`

using keypaths could look like this:

```
extension Sequence {
/// Returns the elements of the sequence, sorted by a (`Comparable`) property indicated by the keypath, optionally using the given predicate as the comparison between elements.
func sorted<T: Comparable>(by keyPath: KeyPath<Self.Element, T>, using sortingFunction: (T, T) -> Bool = (<)) -> [Self.Element] {
self.sorted(by: { sortingFunction($0[keyPath: keyPath], $1[keyPath: keyPath]) })
}
/// Returns the maximum element in the sequence, using the given predicate as the comparison between elements.
func max<T: Comparable>(by keyPath: KeyPath<Self.Element, T>, using comparingFunction: (T, T) -> Bool = (<)) -> Self.Element? {
self.max(by: { comparingFunction($0[keyPath: keyPath], $1[keyPath: keyPath]) })
}
/// Returns the minimum element in the sequence, using the given predicate as the comparison between elements.
func min<T: Comparable>(by keyPath: KeyPath<Self.Element, T>, using comparingFunction: (T, T) -> Bool = (>)) -> Self.Element? {
self.min(by: { comparingFunction($0[keyPath: keyPath], $1[keyPath: keyPath]) })
}
}
```

This is primarily a quality-of-life pitch, but I think it fits in with the pattern established by SE-0249 and would allow for cleanlier `map/flatMap/reduce`

pipelines by reducing repetition and a certain amount of visual clutter, just as `map(\Root.keyPath)`

has done.

**EDIT:**

As @ole has pointed out, similar pitches have been made before, notably by @cal in Sort `Collection` using `KeyPath` (which was pitched before using keypaths in place of closures for higher-order functions made it into the language).

In a follow-up comment posted three years later (after the above change came into effect), @olbo points out that the interchangability of keypaths and closures means that the function can be generalised to accept either form. This means that the implementation of `sorted`

mentioned above can be changed from:

```
func sorted<T: Comparable>(by keyPath: KeyPath<Self.Element, T>, using sortingFunction: (T, T) -> Bool = (<)) -> [Self.Element] {
self.sorted(by: { sortingFunction($0[keyPath: keyPath], $1[keyPath: keyPath]) })
}
```

into:

```
func sorted<T: Comparable>(by keyPath: (Self.Element) -> T, using sortingFunction: (T, T) -> Bool = (<)) -> [Self.Element] {
self.sorted(by: { sortingFunction(keyPath($0), keyPath($1)) })
}
```

@lovee has also pitched a form like this for `min`

/`max`

in Sort(by:) min(by:) max(by:) with keyPaths where he mentions two potential forms for calling the `max`

function:

`let max = sequence.max(by: \.property)`

or

`let max = sequence.max(by: { $0.getSomeValue(from: anotherData) })`

.

Finally, @anthonylatsis proposed Map Sorting in 2019, with the added twist of an `isExpensiveTransform`

parameter to tell the sorting algorithm to cache compared values in case they may be expensive to fetch, as in the `let max = sequence.max(by: { $0.getSomeValue(from: anotherData) })`

example above where `getSomeValue`

may be called repeatedly during the sort. @cal also contributed to that thread with some statistics from the Swift Compatibility Suite regarding typical use cases of `sort`

and `sorted`

, and what optional comparison function was supplied.

That proposal never made it into review, with a follow-up comment:

The discussion has since stalled, and I would appreciate input from other Swift users here.