Motivation
My idea is, that Swift should be more consistent on using the extension
keyword on a protocol
.
Background
The Swift Documentation says:
"Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code"
In case of classes or structs I can extend by adding new methods. I need to define them in the extension and then my class or struct gets a new method.
But Swift goes further and also allows the extension
keyword on a protocol
. The documentation says:
"In Swift, you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of." More is explained here.
My thoughts on this
I think, that this is not the right usage of the extension keyword. With this way, you don't extend the protocol, you implement methods. This can lead to the problem, that you may make mistakes, if you will overwrite the default implementations (look here why).
Also, it's not possible to really extend a protocol like this:
protocol A {
func myFuncA()
}
extension A {
func myFuncB()
// this doesn't work, because Swift now expects the code for the implemenation
// -> error: Expected '{' in body of function declaration
}
And I think, that this should be the right way of extending a protocol. Extending a class means adding more methods, extending a protocol should mean adding more methods, that the class/struct should implement.
Extending a protocol like this could be necessary, if you really want to extend the protocol (or if you need to, because you don't have access to the original code). At the moment, you just can create a new protocol like this:
protocol B: A {
func myFuncB()
}
class MyClass: B { ... }
Of course, that would work perfectly right now, but in my opinion it's inconsistent (you even see it by creating this empty class: Xcode tells you, that it doesn't conform to protocol A and it doesn't conform to protocol B... so it's not an extension, it's just combining two protocols).
My idea for a change
I would suggest to introduce a new keyword for protocol implementations and leave the extension keyword for defining more required methods, that need to be implemented. As example:
Without extension:
protocol A {
func myFuncA()
}
class MyClass: A {
// the class just needs to implement the myFuncA()
func myFuncA() {
...
}
}
With extension:
protocol A {
func myFuncA()
}
extension A {
func myFuncB()
}
class MyClass: A {
func myFuncA() {
...
}
// now the class also needs to implement the extended methods
func myFuncB() {
...
}
}
Now an example for making a default implementation:
protocol A {
func myFuncA()
}
implementation A {
func myFuncA() {
print("I'm a default implementation")
}
}
class MyClass: A {
// now the class can be empty
}
Solving the side problem: Overwriting a default implementation
This suggestions leads to the same side problem that already exists right now and what was the reason for my original posting: If you want to overwrite the default implemenation and if you make a typo at the parameter names while doing this, the compiler wouldn't complain about this. For example:
protocol A {
func myFuncA(parameter1: Int, parameter2: Int)
}
implementation A { // or actually: extension A {
func myFuncA(parameter1: Int, parameter2: Int) {
print("I'm a default implementation. Sum: \(parameter1+parameter2)")
}
}
class MyClass: A {
func myFuncA(param1: Int, param2: Int) {
// there would be no warning, that this doesn't conform to the protocol
}
}
Therefor I would suggest to force the need of the overwrite
keyword:
protocol A {
func myFuncA(parameter1: Int, parameter2: Int)
}
implementation A { // or actually: extension A {
func myFuncA(parameter1: Int, parameter2: Int) {
print("I'm a default implementation. Sum: \(parameter1+parameter2)")
}
}
class MyClass: A {
overwrite func myFuncA(param1: Int, param2: Int) {
// now there would be an error, that the parameters are wrong
}
}
If you wouldn't use the overwrite keyword, the compiler would complain, that there is a default implementation for this method.
Cons
The big problem of this is, that it will break up old code and Xcode would need to refactor all of the old code.
Small solution
The smaller "solution" could be to implement a compiler warning, if there is a typo in the parameters as there is one if you just implement a protocol itself, for example in this code:
protocol A {
func myFuncA(parameter1: Int, parameter2: Int)
}
class MyClass: A {
func myFuncA(param1: Int, param2: Int) {
// error: Method 'myFuncA(param1:param2:)' has different argument labels
// from those required by protocol 'A' ('myFuncA(parameter1:parameter2:)')
}
}