Improving the UI of generics

I outlined the primary reason right after that sentence in the original post:

Trying to put it another way: because Swift has Self types in protocols, and allows them to be used as function arguments, you can write a protocol whose behavior as a type is fundamentally incompatible with its behavior as a generic constraint. If you consider a protocol like Swift's Equatable:

protocol Equatable {
  static func ==(a: Self, b: Self) -> Bool
}

The Self requirement allows the protocol to require that an Equatable type is only comparable to itself, not some arbitrary other Equatable value. This makes Swift protocols able to express more powerful relationships than the features they took syntactic inspiration from, such as Java and C#'s interfaces, but it creates the situation where the type Equatable can't directly satisfy the requirements of the protocol Equatable—two values of type Equatable can dynamically contain different types, but the requirement applies to two values of the same type. Changing the spelling to something like any Equatable doesn't eliminate that situation, but my hope is that it makes it clearer that you're asking for a distinct thing from the protocol, and that it's easier to explain why the type any Equatable doesn't conform to the protocol Equatable than the seemingly-broken statement that Equatable doesn't conform to Equatable.

By contrast, the closest that those other languages' interface features can get to self and associated type requirements is to represent them as generic arguments, this is why Comparable<T> in Java makes you repeat the conforming class name in class Foo implements Comparable<Foo>. And you can only use interfaces as types by providing all of their generic arguments, so you don't have the covariance issues of Swift's type erasure, though at the same time, Comparable<Foo> is unlikely to be very useful as a type because only Foo and its subclasses can usually implement it, so it provides little expressivity beyond using Foo directly. (In the case of Java, you do also have the ? wildcard to get something like Swift's type erasure, though Java's implementation is unsound and has problems of its own.) I do think that the strain on Swift's protocol types would be felt less by typical users if we had the analogous ability to bind their associated types, so that you could write any Sequence<Int> instead of only any Sequence. I talk about that a bit later in this post, but more recently Holly has just begun a pitch for this feature.

21 Likes