[Discussion] Eliding `some` in Swift 6

Having given it a bit more thought, I do think there are some compelling reasons to avoid the elision route. I don't think they're enough to convince me it's the wrong direction, ultimately, but they do give me some pause.

To illustrate, I'll pull up one additional example that would be a somewhat inscrutable (IMO) error under the elision regime:

In the years leading up to the introduction of existential any, it was often discussed that the decision to use bare P for the existential form of the protocol type was made because it is just so attractive to be able to write a protocol type that 'looks just like' any other type. But this caused users to ignore and or neglect important differences between existential types and other types, and made those differences downright invisible at the point of use (modulo non-universal naming conventions like -able), leading us to the eventual deprecation of the bare existential syntax.

However, there are also important differences and limitations when writing generic code, so it's not obvious to me that being able to write some types in a way that 'looks just like' any other type is actually where we want to end up. Yes, automatic opening, (partially) generalized existentials, and all the other generics features in Swift 5.7 will help greatly, but there are fundamental differences between generic and concrete code—is it better for code to have those differences invisible at the point of definition?

When reading code, even if users don't grok what some means in full generality, I think it's at least become ingrained via its usage for opaque types that there's something a little funky going on that makes it not quite like a 'normal' type. In that spirit, reading a function signature like func f(x: some P) at least offers an indication for novice users that x (and f) might not behave just like any other type (and provides an easily searchable handle—"swift type some" provides good results on Google!). For more experienced users who understand some more completely, it offers a lightweight visual indication that the function is generic, without having to already know that P is a protocol as opposed to some other type.

ETA: I think this last sentence is a decent counterpoint to this argument for elision:

If there's a distinction to be understood at all, it will in some cases be invisible even to users who understand generics perfectly well. Rarely do I command-click on the types of each parameter in the signature of a function that I'm trying to understand, and I don't think we should go down a route that would require a user to do so in order to use the function intelligently.

Now, perhaps we think that the considerations when deciding to make a function generic don't rise to the level where it deserves explicit calling out at the point of definition (for both writers and readers), or maybe we think that future language evolution can close the gap enough that generic code really can be totally transparent. But I'm not fully confident that if we allow some elision in Swift 6, we won't find ourselves back here in time for Swift 7 discussing whether we should remove bare P and force users to always specify some or any.

Of course, if allowing some elision in Swift 6 really does make the any transition super painless, maybe revisiting the decision later is okay! In that hypothetical, we tried elision to soften the blow, decided it wasn't worth the costs, and so we really do need to force a mass migration to explicit some and any—but that's what we'll have to do with any anyway if we don't allow elision.

10 Likes