Swift: type does not conform to protocol - swift

protocol A {}
protocol B {
var a: A { get }
}
struct StructA: A {}
struct StructB {
var a: StructA
}
extension StructB: B {}
This produces the error :
Type 'StructB' does not conform to protocol 'B'
The StructA already conform to protocol A, and StructB's property a return StructA type. That seems pretty a protocol B conformed type.
But why?
Xcode version 7.3 which Swift version is 2.2

To better illustrate the problem with your current code, let's say you have a StructC : A.
Your protocol B says that you can assign StructC to a (as it conforms to A) – but StructB says you cannot assign StructC to a StructA type. Therefore StructB doesn't conform to B.
The solution is either to change the type of a from StructA to A as Rahul says, or better yet, you could use generics.
The advantage of using generics is once you create your StructB with a given a – that property's type will be inferred by Swift, giving you better type safety. For example, once you assign a StructA to it, its type will then be StructA. If you assign a StructC to it, its type will be StructC.
To do this, we just have to add an associatedtype to protocol B. This will define a 'placeholder' type that we can then implement in a type that conforms to B. We can then define the generic type T in StructB that will provide the 'implementation' of AType – making sure it conforms to A. Therefore, we are now free to assign either StructA or StructC to a, without losing type safety.
protocol A {}
protocol B {
// new associated type to hold the type of "a" which conforms to A
associatedtype AType:A
var a: AType { get }
}
struct StructA: A {}
struct StructC:A {}
// define the new generic T which conforms to A
struct StructB<T:A> {
// define the type of a as the generic T, which conforms to A (and thus conforms with the protocol)
var a : T
}
extension StructB: B {}
let s = StructB(a: StructA())
s.a // "a" is now of type StructA
let s1 = StructB(a: StructC())
s1.a // "a" is now of type StructC

Because Swift is statically typed and does not depend on dynamic dispatch. You could do something like below.
import UIKit
protocol A {}
protocol B {
var a: A { get }
}
struct StructA: A {}
struct StructB {
var a: A = StructA()
}
extension StructB: B {}

I am reworking this code from swift 3.0.
extension WallPost: PFSubclassing {
static func parseClassName() -> String {
return "WallPost"
}
}
This generates the error:
Type 'WallPost' does not conform to protocol 'PFSubclassing'
Unavailable class method 'object()' was used to satisfy a requirement of protocol 'PFSubclassing'
Any idea of why this is happening and how I can resolve it? I wanted to fix this before updating to swift 4.0 / 5.0
Thanks so much for the help!

Related

How can I use a generic-type constraint extension for a class with a `Codable` type constraint?

Say my class definition is:
class Foo<T: Codable> {
let bar: T
}
I want to extend arrays of this type:
extension Array where Element: Foo<Codable> { /* do something based on `bar` values */ }
This produces the error
Protocol 'Codable' (aka 'Decodable & Encodable') as a type cannot conform to 'Decodable'
I did read in another question that conforming T to Encodable/Decodable isn't possible if T == Encodable/Decodable since a protocol can't conform to itself, but this is only for a certain property so I'm having trouble wrapping my head around it. Is there any way to achieve this?
I think is better to use protocol instead class like this.
protocol FooProtocol {
associatedtype T : Codable
var bar: T {get set}
}
extension Array where Element: FooProtocol {
}

Need to satisfy Swift protocol requirement by using a specific subclass of the requirement (or type that conforms to it)

I have a protocol that I've created (in Swift 4.2), and one of its requirements is a property that is of the same type as the protocol itself.
As an example, I have a protocol defined like so:
protocol A {
var a: A? { get set }
}
I have several Models that conform to this protocol:
class Model1: A {
var a: A?
}
class Model2: A {
var a: A?
}
For one of my models, I need to satisfy the protocol requirement by being more specific for the property defined by variable a (i.e. the variable with the protocol type). So for example I may want to implement Model2 as:
class Model2: A {
var a: Model1?
}
In this case since Model1 conforms to the protocol A you would expect this to be able to satisfy the protocol requirement, however I get an error instead:
Type 'Model2' does not conform to protocol 'A'
Why is this happening, and what can I do to make it work as described above?
Appendix
I've modelled the above scenario in an Xcode Playground and here is a screenshot of the error I'm seeing.
To conform to protocol A, Model2 would need a member var a that allows storing a reference to anything conforming to protocol A, not just a reference to a Model1. So you can't do this.
You could do this with associated types:
protocol A {
associatedtype B: A
var a: B? { get }
}
This would let you declare Model2 with the specificity you wish:
class Model2: A {
var a: Model1?
}
But unfortunately, that would mean you could no longer declare variables of type A. To fix that, you could use generic models:
class Model1<T: A>: A {
var a: T?
}

Swift protocol as generic type

I have this kind of code:
protocol MyProtocol {
}
class P1: MyProtocol {
}
class P2: MyProtocol {
}
class C <T: MyProtocol> {
}
Then i need to define a variable to delegate all kinds of C<MyProtocol>:
var obj: C <MyProtocol>
But compile error comes:
Using 'MyProtocol' as a concrete type conforming to protocol 'MyProtocol' is not supported
How can I do?
This code:
class C <T: MyProtocol> { }
Means that C is a generic class that can specialize on any type T that conforms to MyProtocol.
When you declare:
var obj: C <MyProtocol>
You are (I think) trying to say that the var obj will be an instance of C specialized to some type that conforms to MyProtocol,but you can't specialize a generic class on a protocol type, because there is no such thing as a direct concrete instance of a protocol. There can only be instances of a type conforming to the protocol. And there can theoretically be many different types that conform to the protocol. So that notation doesn't really tell the compiler which specific specialization of C to use.
This shouldn't be a problem though, because you can write things like:
var obj: C<P1> = C<P1>()
or
var obj = C<P2>() // type is inferred
And within your class C you can still treat any uses of T as conforming to MyProtocol. So I think this should give you everything you need, as long as you remember that an instance of a generic class must be specialized to a single specific concrete type, not a protocol which could represent many possible concrete types.
You usually don't need to declare type for a Swift's variable. The compiler can infer type in most cases. Also, for generic class, you should let the compiler figure out what the generic classes resolve to:
class C<T: MyProtocol> {
var value: T
init (value: T) {
self.value = value
}
}
var obj = C(value: P1()) // type: C<P1>
// or:
var obj = C(value: P2()) // type: C<P2>

How to make protocol associated type require protocol inheritance and not protocol adoption

In my swift project I have a case where I use protocol inheritance as follow
protocol A : class{
}
protocol B : A{
}
What Im trying to achieve next is declaring another protocol with associated type, a type which must inherit from protocol A. If I try to declare it as :
protocol AnotherProtocol{
associatedtype Type : A
weak var type : Type?{get set}
}
it compiles without errors but when trying to adopt AnotherProtocol in the following scenario:
class SomeClass : AnotherProtocol{
typealias Type = B
weak var type : Type?
}
compilation fails with error claiming that SomeClass does not conform to AnotherProtocol. If I understood this correctly it means that B
does not adopt A while Im trying to declare and asking you on how to declare an associated type which inherits from protocol A?
I made the above assumption based on fact that the following scenario compiles just fine
class SomeDummyClass : B{
}
class SomeClass : AnotherProtocol{
typealias Type = SomeDummyClass
weak var type : Type?
}
This is pretty interesting. It appears that once you constrain the type of an associatedtype in a given protocol, you need to provide a concrete type in the implementation of that protocol (instead of another protocol type) – which is why your second example worked.
If you remove the A constraint on the associated type, your first example will work (minus the error about not being able to use weak on a non-class type, but that doesn’t seem to be related).
That all being said, I can't seem to find any documentation in order to corroborate this. If anyone can find something to back this up with (or completely dispute it), I’d love to know!
To get your current code working, you can use generics. This will actually kill two birds with one stone, as both your code will now compile and you'll benefit from the increased type safety that generics bring (by inferring the type you pass to them).
For example:
protocol A : class {}
protocol B : A {}
protocol AnotherProtocol{
associatedtype Type : A
weak var type : Type? {get set}
}
class SomeClass<T:B> : AnotherProtocol {
typealias Type = T
weak var type : Type?
}
Edit: It appears the above solution won't work in your particular case, as you want to avoid using concrete types. I'll leave it here in case it's useful for anyone else.
In your specific case, you may be able to use a type erasure in order to create a pseudo concrete type for your B protocol. Rob Napier has a great article about type erasures.
It's a bit of a weird solution in this case (as type erasures are normally used to wrap protocols with associatedtypes), and it's also definitely less preferred than the above solution, as you have to re-implement a 'proxy' method for each method in your A & B protocols – but it should work for you.
For example:
protocol A:class {
func doSomethingInA() -> String
}
protocol B : A {
func doSomethingInB(foo:Int)
func doSomethingElseInB(foo:Int)->Int
}
// a pseudo concrete type to wrap a class that conforms to B,
// by storing the methods that it implements.
class AnyB:B {
// proxy method storage
private let _doSomethingInA:(Void)->String
private let _doSomethingInB:(Int)->Void
private let _doSomethingElseInB:(Int)->Int
// initialise proxy methods
init<Base:B>(_ base:Base) {
_doSomethingInA = base.doSomethingInA
_doSomethingInB = base.doSomethingInB
_doSomethingElseInB = base.doSomethingElseInB
}
// implement the proxy methods
func doSomethingInA() -> String {return _doSomethingInA()}
func doSomethingInB(foo: Int) {_doSomethingInB(foo)}
func doSomethingElseInB(foo: Int) -> Int {return _doSomethingElseInB(foo)}
}
protocol AnotherProtocol{
associatedtype Type:A
weak var type : Type? {get set}
}
class SomeClass : AnotherProtocol {
typealias Type = AnyB
weak var type : Type?
}
class AType:B {
// implement the methods here..
}
class AnotherType:B {
// implement the methods here..
}
// your SomeClass instance
let c = SomeClass()
// set it to an AType instance
c.type = AnyB(AType())
// set it to an AnotherType instance
c.type = AnyB(AnotherType())
// call your methods like normal
c.type?.doSomethingInA()
c.type?.doSomethingInB(5)
c.type?.doSomethingElseInB(4)
You can now use the AnyB type in place of using the B protocol type, without making it any more type restrictive.

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?
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.
I just ran into this problem too. Although I too would like a better understanding of why this is so, the Swift language reference (the guide says nothing about this) has the following from the Generic Parameters section:
Where Clauses
You can specify additional requirements on type parameters and their
associated types by including a where clause after the generic
parameter list. A where clause consists of the where keyword, followed
by a comma-separated list of one or more requirements.
The requirements in a where clause specify that a type parameter
inherits from a class or conforms to a protocol or protocol
composition. Although the where clause provides syntactic sugar for
expressing simple constraints on type parameters (for instance, T:
Comparable is equivalent to T where T: Comparable and so on), you can
use it to provide more complex constraints on type parameters and
their associated types. For instance, you can express the constraints
that a generic type T inherits from a class C and conforms to a
protocol P as <T where T: C, T: P>.
So 'Self' cannot be a struct or emum it seems, which is a shame. Presumably there is a language design reason for this. The compiler error message could certainly be clearer though.
As Foo is an existing type, you could simply extend it this way:
struct Foo { // <== remove MyProtocol
let myVar: String
init(myVar: String) {
self.myVar = myVar
}
}
// extending the type
extension Foo: MyProtocol {
func bar() {
print(myVar)
}
}
From The Swift Programming Language (Swift 2.2):
If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined.