protocol inheritance

I have a couple of issues. The first is I want to be able to do this


protocol A {

static func someMethod() -> Self?

}


extension A {

static func someMethod() -> Self? {

...

}

}


protocal B: A {

}


extension B {

static func someMethod() -> Self? {

...

call protocol A's someMethod

...

}

}


Is there a way to do this? I need to add some additional behavior to protocol B and do all of the code in protocol A's protocol extension. The best I could cope up with is have exension A have a doSomeMethod() method that does the actual work, then have both A and B call that. Is there a way to do the equivalent of super.someMethod() which doesn't work because it's not a class.

With protocol extensions, you can't override methods (even if they wouldn't be static). You can add a new implementation and if this implementation exists already, you are shadowing the former implementation. The former implementation will still be there, but it's not accessible in your new implementation.


In your example, you are really adding a new static method to protocol B. I would give it a different name because it's a different method and then all your problems go away:


protocol A {
  init()
  static func someMethodA() -> Self?
}
extension A {
  static func someMethodA() -> Self? {
    print("someMethodA()")
    return Self()
  }
}
protocol B: A {
  static func someMethodB() -> Self?
}
extension B {
  static func someMethodB() -> Self? {
    print("someMethodB()")
    return someMethodA()
  }
}


Here's an example for how this can be used:


final class BImpl: B {
  required init() {}
}
BImpl.someMethodB()  // will print someMethodA() followed by someMethodB()
BImpl.someMethodA()  // will print someMethodA()

giving it a different name doesn't work. I'm loading resources on demand, some can change outside the app so need to be loaded on demand each time, others cannnot change outside the app (but more instances can be created) so can be cached. SOme of these lists are short and all objects will likely be used so shoudl be loaded all at once, other lists are long and only some objects will be used so need to just be loaded as need.


protocal loadedObjcts:class {
     static func classSpecificType() -> String
     static func loadObject(id:Iint) -> Self?
}
extension loadedObjcts {
     static func loadObject(id: Int) -> Self? {
          // code to load the object
     }
}

protocal loadedStaticOjects: loadedObjects {
     static var cachedObjects[Int:Self] {get set}
}



extension loadedStaticOjects {
     static func loadObject(id: Int) ?Self {
          if cachedObjects[id] == nil {
               cachedObjects[id] = // code to load the object

          }
          return cachedObjects[id]

     }
}

protocal preloadedStaicOjects: loadedStaticObjects {
     static func loadObject(id:int) {
          if cachedObjects.size == 0 {
               // code to preload them all
          }
          // need to do the loadStaticObjects logic above to catch potential new cases
     }
}


I also have a class hierarchy, each of the final classes implement the appropriate protocol and get the desired behavor. Clients just treat them all as implementing the loadedObjects protocol. They really don't need to know or care if they implement somethign different.


I can change the body fo the first two protocols so that they call a method that's only defined in the extension. The problem is I can't set a requirement where that method is only called by the loadObjects method and callign it otherwise breaks everything.


Waht I really need to be able to do is


let object = super.loadObject[id]


or somethign equivalent without exposing new methods that shouldn't be ever called by anythign other than a loadObject method.

I also have a class hierarchy, each of the final classes implement the appropriate protocol and get the desired behavor. Clients just treat them all as implementing the loadedObjects protocol. They really don't need to know or care if they implement somethign different.


The entire discussion is moot, because your "loadObject" method in your loadedStaticObjects extension will never be called anyway. Methods in protocol extensions are statically dispatched. What this means is that callers need to know what type of object they're dealing with; if the client only knows that it has a loadedObject, then loadedObject's version of the method will be called.


Observe:


protocol Foo {}
extension Foo {
    func say() {
        print("foo")
    }
}
protocol Bar: Foo {}
extension Bar {
    func say() {
        print("bar")
    }
}
class Baz: Bar {}
let obj: Bar = Baz()
obj.say()


When running this, "bar" is logged. However, do it like this:


protocol Foo {}
extension Foo {
    func say() {
        print("foo")
    }
}
protocol Bar: Foo {}
extension Bar {
    func say() {
        print("bar")
    }
}
class Baz: Bar {}
let obj: Foo = Baz()
obj.say()


and suddenly "foo" is logged instead of "bar". So, what type the client knows about determines what method is called, and the decision is made at compile time. It's more like C++ than Objective-C.

I think your example is misleading a little. You are modeling methods that are statically dispatched, but you could equally model a dynamic dispatch. Just put method `say` into protocol `Foo` and the dispatch is dynamic and also the second example prints "bar".


protocol Foo {
  func say()
}
extension Foo {
  func say() {
    print("foo")
  }
}
protocol Bar: Foo {}
extension Bar {
  func say() {
    print("bar")
  }
}
class Baz: Bar {}
let bar: Bar = Baz()
let foo: Foo = bar
bar.say() // prints "bar"
foo.say() // prints "bar"

I can only repeat what I wrote before: what you are trying to do won't work in Swift. There is nothing such like "super" since there are no superclasses at all involved here. Via your extensions, you are introducing new static methods with the same name which just shadow the existing methods.

Ah, you're right. I had thought declaring them in the protocol and declaring them in the extension would be equivalent, since both have the same visibility, but adding a declaration to the protocol does indeed cause Bar's implementation to be consistently used. Well, this makes protocol extensions a lot more useful. Thanks!

while the protocol isn't a class, but there is dynamic dispatching. The language should allow super or some equivlant mechanism to call the parent protocol's extension. It's a common pattern to use dynamic dispatching to extend functionality. THe workarounds for not having the equivalent to super allow for potential client errors that otherwise couldn't happen,


In my initial post I wanted to make sure I wasn't missing somethign in the language and if I wasn't, then I wanted to point out a way the language could be improved. I don't see any technical reason why something equivalent to super couldn't work in this situation. Dynamic dispatching should always have an equiavelent to super. super is actually a static dispatch.

in this case it's not as bad as I thought because i can mark the seperate implementation as private final, so the access control is there and the resulting code should get optimized to be effectively the same is if there were an equivalent to super, it just doesnt' feel right to have have to do this to access the parent implementation vs being able to use something equivalent to super.

There's no way to do this today (other than to separate the implementation of A.someMethod into another function), but please file a bug report with your feature request!

protocol inheritance
 
 
Q