Problem description:
I keep getting this compiler error when trying to use variables whose type is declared as conforming to a protocol:
Protocol type
FooProtocol
cannot conform toFooProtocol
because only concrete types can conform to protocols.
Could someone please let me know if this is a bug, or expected behavior? If it's expected, why? I mean, what is the point of protocols if you cannot use a given instance purely on the basis of its conformance to a protocol?
Example:
Given:
protocol FooProtocol { var bar: Int { get set } }
class FooClass: FooProtocol { var bar = 42 }
struct Bar<F: FooProtocol> {
typealias MyFoo = F
var foo: MyFoo
init(foo: MyFoo) { self.foo = foo }
}
struct Whee {
var someSpecificFoo: FooProtocol
func process() { let bar = Bar(foo: someSpecificFoo) } // error line
}
var whee = Whee(someSpecificFoo: FooClass())
print(whee.someSpecificFoo.bar)
Strangely, the compiler fails with:
Protocol type
FooProtocol
cannot conform toFooProtocol
because only concrete types can conform to protocols.
This seems like a buggy error, because this statement is basically incorrect. The compiler ought to be able to recognize that someSpecificFoo
is a concrete instance conforming to FooProtocol
because that's what var someSpecificFoo: FooProtocol
means.
If we change the declaration to, var someSpecificFoo: some FooProtocol
, all this does is to change the error to:
Property declares an opaque return type, but has no initializer expression from which to infer an underlying type
Why does the compiler now fail to auto-synthesize an initializer expression like normal?
Even if we add an explicit initializer, it will still fail. Adding:
init<F: FooProtocol>(foo: F) { self.foo = foo }
... just changes the error message to:
Cannot assign value of type
F
to typesome FooProtocol
Why can't the first error tell us how to fix the problem, instead of suggesting a corrective action that (if you try it) will just change the error to something else?
More importantly, why can't F be considered some FooProtocol
? F conforms to FooProtocol by definition.
And in my codebase there is only one type that conforms to FooProtocol
, which means that even if the compiler just guessed, it would have a 100% chance of being correct about what the actual underlying type must be. So why do we get these errors?
Workarounds:
Just on a hunch I tried adding @objc
to the protocol declaration and import Foundation
to the top line, and boom, now the code works perfectly.
But why?
And are there downsides to adding @objc
here? If so what are they? If not, why isn't it just like that by default?