Public instance method in an extension with internal requirements

I'm playing around with Swift 5 a little and I was thinking if we can potentially lower the strictness of the error message in the future:

Cannot declare a public instance method in an extension with internal requirements

protocol P {}

public class Base<Derived> {}

extension Base where Derived: P {
  public func bar() { ... }
}

// CRTP: Thank you Slava 🍻
public final class SubClass: Base<SubClass>, P {}

Sure the extension shouldn't be visible for good reasons, but could we make the method available as a public member of module internal but public subclasses? In other words the extension won't be visible for the module user as an extension of Base, but he may see an extension on all public subclasses of Base with that method.

extension SubClass {
  public func bar()
}

With CRTP I would need to rename the method on the super-class if I want to expose it in a subclass to the public, because overriding methods declared in an extension is not yet supported:

extension Base where Derived: P {
  func _bar() { ... }
}

public final class SubClass: Base<SubClass>, P {
  public func bar() {
    _bar()
  }
}

This doesn't work because the calling convention for bar() requires passing information about how self conforms to P, and an external client doesn't have that information. Your _bar workaround is the recommended pattern for now; a way to make it slightly prettier would be to formalize the @nonoverriding attribute, so that you could make the subclass bar shadow the base class one.

  public func bar() {
    let baseSelf: Base<SubClass> = self
    baseSelf.bar() // not ambiguous because we upcasted
  }
1 Like

I see, thank you. The idea was too good to be true. ;)

1 Like