Why Is Covariant Self more flexible on protocols than classes?

The keyword Self inside a class is not a generic parameter, it is its own special thing primarily meant for Objective-C interoperability (it’s spelled instancetype there). It is always the dynamic type of the instance and not the static type at the call site. Eg,

protocol P {}

class Base: P {
  func f() { print(Self.self) }
}

extension P {
  func g() { print(Self.self) }
}

class Derived: Base {}

(Derived() as Base).f()
(Derived() as Base).g()

Given this behavior returning a Foo<Self> from a class method is unsound because we might get Foo<Base> or Foo<Derived> dynamically, but the two types are distinct and we don’t know which we would get.

9 Likes