I have a protocol that has a static method with a default parameter. I want to change the default value in a class that implements the protocol. Essentially doing what is easily done with classes and super.
I only have a solution when the Protocol has no associated type.
The following code works, but as soon as you uncomment the associated type declaration, it doesn't compile.
protocol Protocol {
// associatedtype AssociatedType
}
extension Protocol {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol {
typealias AssociatedType = T
func sayHello(name: String = "Stack Overflow") {
// Uncommenting the Protocol.AssociatedType causes:
// Protocol can only be used as a generic constraint because it has associated type requirements
(self as Protocol).sayHello(name)
}
}
Class<()>().sayHello()
I do understand why it doesn't compile: Protocol has no concrete type for AssociatedType.
So maybe the question should read "Can I explicitly specialize a protocol?", to which I believe the answer is no.
I have a partial workaround. But even when it works, it sucks.
Especially when you consider that I'm writing a library where sayHello is public, so the following workaround forces me to have a second protocol, which has to be public, but is useless.
Here's the workaround:
protocol Parent {}
protocol Protocol: Parent {
associatedtype AssociatedType
}
extension Parent {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol {
typealias AssociatedType = T
func sayHello(name: String = "Stack Overflow") {
(self as Parent).sayHello(name)
}
}
Class<()>().sayHello()
But this doesn't work for me, because my sayHello uses the associated type. So it can't be extracted to another protocol.
Just to be sure I'm clear, here's what I'd like, only substituting the class for a protocol:
class Protocol<T> {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol<T> {
override func sayHello(name: String = "Stack Overflow") {
super.sayHello(name)
}
}
Class<()>().sayHello()
You're trying to reinvent inheritance in protocols, and there is no such thing. But it is trivial to get what you're talking about; just say what you mean. You don't mean "I want to do the thing I inherited." You mean "I want to do some common behavior." Just provide a name for that common behavior. This removes all ambiguity about which one you mean.
The one frustrating part about this is that Swift provides no way to limit
defaultSayHelloto implementers ofProtocol. So technically anyone can call it. It can sometimes be worth prefixing it with an_to indicate that outsiders shouldn't. This is a basic access control problem in protocols, having nothing to do with this specific question; it comes up all the time when you want "things my implementers can use on themselves, but shouldn't be called randomly." Swift doesn't have a solution for that today.