How to give the last parameter its default to `<` operator? func f<Target: Comparable>(_ a: Target, _ b: Target, areInIncreasingOrder: (Target, Target) throws -> Bool /* = Target.< */) rethrows

pretty much like sort(by:) but I want the parameter to have default to <:

// how to provide Comparable's `<` as default for `areInIncreasingOrder`?
func f<Target: Comparable>(_ a: Target, _ b: Target, areInIncreasingOrder: (Target, Target) throws -> Bool /* = Target.< */) rethrows -> Bool {
    try areInIncreasingOrder(a, b)
}


// want the following two lines to be the same
f(1, 2, areInIncreasingOrder: <)
// omiting the last param
f(1, 2)

Use parentheses: areInIncreasingOrder: (Target, Target) throws -> Bool = (<).

You'll see that at least the current version of Swift regards the default parameter to be throws, which requires you to use try even though < doesn't throw:

f(1, 2)
// Error: call can throw but is not marked with 'try'
// Note: call is to 'rethrows' function, but a defaulted argument function can throw

I think that one's a bug but someone else may know better. Perhaps @Slava_Pestov, who's most recently worked on the rethrows checking code, has thoughts?

2 Likes

The odd throws issue—which seems like a bug to me too—can be worked around by instead creating two functions the old fashioned way:

func f<Target: Comparable>(
  _ a: Target,
  _ b: Target,
  areInIncreasingOrder: (Target, Target) throws -> Bool
) rethrows -> Bool {
    try areInIncreasingOrder(a, b)
}
func f<Target: Comparable>(
  _ a: Target,
  _ b: Target
) -> Bool {
  return f(a, b, areInIncreasingOrder: <)
}
1 Like

(<)

Thank you for the answer. The call site is just a naked "<", I just could not think of surrounding the operator with parens. It's not very symmetric, would be nice if the default can be the same as the call site. Small nitpick.

This is a duplicate of SR-1534, SR-2979, SR-7611, SR-12109, SR-12389.

2 Likes