TSPL Pitch: Moving discussion of existentials later in the book

Currently, TSPL introduces boxed protocol types (also known as existential types) as part of the discussion of protocols, before either generics or opaque types are introduced, and it frames existentials as a common thing to use rather than an advanced tool for special cases. This ordering comes from the early days of Swift, when the generics system was less capable, when we didn’t even have opaque types, and when the “tripping hazards” around existentials were less well known. We've recognized that the bare-protocol syntax for existentials is an attractive nuisance and we're changing the syntax accordingly — TSPL should also change its ordering, to avoid introducing this less-common feature before the things you usually want instead.

The approach I’m working on is as follows:

  • In the Protocols chapter, replace the discussion of existentials with a summary of the ways you can use a protocol as a type, linking forword to the full discussions of generics and existentials and opaque types.
  • Move the discussion of existentials from Protocols to Opaque Types, renaming that chapter to Opaque and Boxed Types.
  • Add a new Boxed Protocol Type section in the reference, to discuss the any keyword.

Another approach I considered was discussing existentials in Generics or in their own chapter. Conceptually, existentials and generics don’t have a lot in common, so combining them in one chapter doesn’t really make sense. Existentials and opaque types are conceptually similar enough that they can go together, and that chapter already includes a section that compares and contrasts them. Making a new chapter (probably after Opaque types) is an option, but the material is short enough that it doesn’t quite need its own chapter. A new chapter would also have ordering challenges: Existentials should be introduced after generics and opaque types, because they are the least common of the ways to use protocols as a type, but they need to come before the comparison between opaque and existential types.

My work so far is on the existential_any_88208011 branch in my fork.

12 Likes

This looks pretty great, Alex! Personally, I like the approach.

I think the new subsection on existential ("Boxed") types could be strengthened by a heading and some content analogous to the one for opaque types that's titled "The Problem That Opaque Types Solve"—currently, your draft retains the existing text about what users can use existentials for, but it doesn't really say anything about what users should want to use them for (and the main one I can think of here would be heterogeneous collections).

I also agree that it's wise to call out the performance penalty of using an existential type but at the level of detail you've chosen (rather than going into the details of inline buffer size, etc.). I would suggest, however, hedging that Swift may add a level of indirection rather than stating it as fact (since in the most straightforward cases where they're currently used unnecessarily the compiler of course reserves the right to optimize that out).

Rather, in terms of user-facing language semantics, I'd throw in a mention there (even a short one) that because the underlying type can vary at runtime, there isn't a statically known underlying type, and for that reason not all APIs (nor protocol conformances) of the underlying type can be made available through the box. It would be really helpful if then in the corresponding dedicated subsection on existentials some more detailed but still didactically appropriate treatment of this issue could be included, as it is a very common question here on the user forums and probably more of what users trip up on when they use existentials than the performance bit. (Feel free to lift any text I've contributed to the educational notes in the Swift repository on this issue.)

3 Likes