[Discussion] Eliding `some` in Swift 6

While not its intention, this code makes one of the clearest cases for why some should be elided. It's true that essentially extending a protocol is extension some Protocol, to require an explicit some to all protocol extensions would be the kind of ceremony that goes against Swift's vision of clear concise syntax in the default case. It would be like introducing a sync keyword to match the async keyword.

The beauty of protocol extensions is that users are writing generic code without even knowing it. And it is extremely rare that they need to know it. Instead, they extend Collection like they extend Array and are happy that this works.

Similarly, they will not need to know in most cases that when they write f(_ c: Collection<Int>) that they are writing generic code. They will write the syntax that they assume works (especially when coming from the many languages that have basically this exact syntax) and happily discover that it does.

The curse of P defaulting to any P today is that when they write the "natural" syntax, the syntax they learned in other languages, they are writing the thing they probably don't want – there's very few reasons to write a function that takes any instead of some, but there are more reasons to write some instead of any. It's wonderful that these two options now have parity in terms of concision, but we should go further. The more general, useful option should be easier.

Now the pushback here may be, ah, but then users may be confused, because an argument of P in Swift will not mean passing a supertype like it does in Java or Objective-C. And it's true that they differ in subtle ways. And these subtle ways are more common than when writing protocol extensions. But the first time they use the feature is not the time to teach these differences, where you will bother them with extraneous details they won't yet need to understand. That time, instead, is when they hit those differences:

func f(_ maybe: Collection<Int>?) { ... }
let a: any Collection<Int> = [1,2,3]
// error: f needs to know the exact type of `a` but it might be nil.
f(a)

// error: All return statements in f must have matching underlying types.
func g() -> Collection<Int> {
  if ... {
    return [1,2,3]
  } else {
    return Set([1,2,3])
}
5 Likes