Christopher Christopher - 4 months ago 35
Swift Question

Protocol extensions on Structs causes compile error 'Self' constrained to non-protocol type

I'm attempting to apply a constrained protocol extension to a struct (Swift 2.0) and receiving the following compiler error:


type 'Self' constrained to non-protocol type 'Foo'


struct Foo: MyProtocol {
let myVar: String

init(myVar: String) {
self.myVar = myVar
}
}

protocol MyProtocol {
func bar()
}

extension MyProtocol where Self: Foo {
func bar() {
print(myVar)
}
}

let foo = Foo(myVar: "Hello, Protocol")
foo.bar()


I can fix this error by changing
struct Foo
to
class Foo
but I don't understand why this works. Why can't I do a
where Self:
constrained protocol a struct?

Answer

This is an expected behaviour considering struct are not meant to be inherited which : notation stands for.

The correct way to achieve what you described would be something like equality sign like:

extension MyProtocol where Self == Foo {
    func bar() {
        print(myVar)
    }
}

But this doesn't compile for some stupid reason like:

Same-type requirement makes generic parameter Self non-generic

For what it's worth, you can achieve the same result with the following:

protocol FooProtocol {
  var myVar: String { get }
}
struct Foo: FooProtocol, MyProtocol {
  let myVar: String
}

protocol MyProtocol {}
extension MyProtocol where Self: FooProtocol {
  func bar() {
    print(myVar)
  }
}

where FooProtocol is fake protocol which only Foo should extend.

Many third-party libraries that try to extend standard library's struct types (eg. Optional) makes use of workaround like the above.

Comments