Projection in collections methods

You just need another sorted overload.

let now: Date = .now
let myData: [MyData] = [
  .init(time: .distantFuture),
  .init(time: .distantPast),
  .init(time: now)
]

#expect(
  myData.sorted(by: \.time).map(\.time) == [
    .distantPast, now, .distantFuture
  ]
)
public extension Sequence {
  @inlinable func sorted<each Comparable: Swift.Comparable, Error>(
    by comparable: (Element) throws(Error) -> (repeat each Comparable)
  ) throws(Error) -> [Element] {
    do {
      return try sorted { try (repeat each comparable($0)) < (repeat each comparable($1)) }
    } catch {
      throw error as! Error
    }
  }
}

@inlinable public func < <each Element: Comparable>(
  _ element0: (repeat each Element),
  _ element1: (repeat each Element)
) -> Bool {
  for elements in repeat (each element0, each element1) {
    if elements.0 < elements.1 { return true }
    if elements.0 > elements.1 { return false }
  }
  return false
}

(I've tried to figure out how/if you could pass in >, instead of having to reverse the sorted array, but the compiler gets crashy with parameter packs. It's easy if you don't use packs.)

let sortedDates = myData.sorted(by: \.time).map(\.time)
#expect(sortedDates == [.distantPast, now, .distantFuture])
#expect(myData.sorted(by: \.time, >).map(\.time) == sortedDates.reversed())
public extension Sequence {
  @inlinable func sorted<Comparable: Swift.Comparable, Error>(
    by comparable: (Element) throws(Error) -> Comparable,
    _ areInIncreasingOrder: (Comparable, Comparable) throws(Error) -> Bool = (<)
  ) throws(Error) -> [Element] {
    do {
      return try sorted {
        try areInIncreasingOrder(comparable($0), comparable($1))
      }
    } catch {
      throw error as! Error
    }
  }

  // This should be covered by the other overload, 
  // but using that one with `Never` crashes the compiler.
  @inlinable func sorted<Comparable: Swift.Comparable>(
    by comparable: (Element) -> Comparable,
    _ areInIncreasingOrder: (Comparable, Comparable) -> Bool = (<)
  ) -> [Element] {
    sorted {
      areInIncreasingOrder(comparable($0), comparable($1))
    }
  }
}