3

In C#, there is this great language feature called "explicit interface implementations" that allows you to implement two or more interfaces where the names of the interfaces' methods conflict. It can also make a method do one thing when you call it using an object of the enclosing type, and do another thing when you cast it to the interface type then call the method. I am wondering if there is such a thing in Swift. Does this conflict with any of swift's ideologies?

Basically I want to do something like this:

struct Job: CustomStringConvertible {
    var location: String
    var description: String
    var CustomStringConvertible.description: String {
        return "Work Location: \(self.location), description: \(self.description)"
    }
}

Job(location: "Foo", description: "Bar").description // "Bar"
(Job(location: "Foo", description: "Bar") as CustomStringConvertible).description // "Work Location: Foo, description: Bar"

I found this on the Internet but I don't think that's relevant because it appears to be about forcing method overriding in child classes.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Your question is not entirely clear to me, a type *can* adopt two protocols having identical method names, compare http://stackoverflow.com/questions/31586864/swift-2-0-protocol-extensions-two-protocols-with-the-same-function-signature-c. – Martin R May 02 '17 at 17:08
  • I know that. But I want a type to implement two protocols with identical method signatures _differently_ like in the MSDN example. And the main thing I want is actually to achieve something like the code snippet in the question i.e. normally, `someJob.description` returns one value, but when you access `description` by doing `(someJob as CustomStringConvertible).description` it returns another value. @MartinR – Sweeper May 02 '17 at 17:16
  • The problem is, I am not sure whether this is a good fit for swift. That's why I asked `Does this conflict with any of swift's ideologies?`. Also, I don't really know how to write a proposal... @matt – Sweeper May 02 '17 at 17:42
  • 3
    The deeper question isn't "does it conflict with ideology" but rather "what is the important problem that this allows developers to solve in an elegant way?" Every new feature is complexity. What does this feature buy us, and how is it worth that complexity? The only benefit I'm seeing here is in cases where `Job` does not already conform to `CustomStringConvertible`, but does happen to implement a method with the same name, but conflicting semantics, and (for some unknown reason), it is impossible to change `Job`. So it's a confusing work-around for an awkward problem. – Rob Napier May 02 '17 at 17:51
  • 3
    Personally I don't see why this is a "great language feature". If I am allowed to call a duck a cat, and if when I tell it to quack it then meows instead of quacking, that isn't "great" — it's "insane". The whole point of polymorphism is that an object has _integrity_; its implementation of a method depends on what it _is_, not on how you _cast_ it. Protocol extensions _already_ mess this up enough as it is. – matt May 02 '17 at 17:54

1 Answers1

3

Protocol extensions basically already do what you're describing:

protocol Cat {
}
extension Cat {
    func quack() {
        print("meow")
    }
}
class Duck : Cat {
    func quack() {
        print("quack")
    }
}
let d = Duck()
d.quack() // quack
(d as Cat).quack() // meow
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • And, I may add, to the extent that protocol extensions _do_ already do what you're describing, they are a horror. This behavior has confused the heck out of a very large number of programmers. – matt May 02 '17 at 18:01
  • Oh, I never thought that protocol extensions behave like this! – Sweeper May 02 '17 at 19:15
  • 3
    @Sweeper: Just note that this works only if the method is *not* listed in the protocol definition itself. If you add `func quack()` to `protocol Cat` then the duck quacks, no matter how you call it. – Martin R May 03 '17 at 09:34