Inconsistent ergonomics with implicitly opened existentials: key path closures vs. functions

Given this…

protocol P {
  associatedtype T
}

let sequence: some Sequence<any P> = []

…I can understand why, because of the need for potentially multiple function specializations, this first filter compiles, but the second does not.

func function(_: some P) -> Bool {
  true
}

var filtered = sequence.filter { function($0) }
filtered = sequence.filter(function) // Type 'any P' cannot conform to 'P' 🙃

That wouldn't bug me so much, except that

extension P {
  var property: Bool { true }
}

filtered = sequence.filter(\.property)

compiles, generating "{ $0.property }".

I figure, if you've got a named function, it should get the same promotion—keeping it as a typed closure in this context isn't useful. Disagree?


Inspiration for my experimenting: I watched @hborla's excellent Embrace Swift generics from WWDC and thought it was lame that she had to use a for loop instead of

func feedAll(_ animals: [any Animal]) {
  animals.forEach(feed)
}
8 Likes

Personally, I prefer for-in loops to .forEach, so I would have written it this way even if I could have used .forEach :slightly_smiling_face:

17 Likes