Decodable conformance with other protocols in Swift - swift

The issue is when a struct conforms to a protocol (let's call it PA) and Decodable, but PA imposes a property with a type that is not Decodable. Example:
protocol PA {
var b: [PB]? { get }
}
protocol PB {}
struct SA: PA, Decodable {
let b: [PB]? // SA's conformance to Decodable wants this to be [Decodable], but PA's conformance imposes [PB]
}
struct SB: PB, Decodable {}
the code above refuses to compile, with:
error: type 'SA' does not conform to protocol 'Decodable'
note: cannot automatically synthesize 'Decodable' because '[PB]?' does not conform to 'Decodable'
Changing that line to:
let b: [PB & Decodable]?
does not work either and gives:
error: type 'SA' does not conform to protocol 'PA'
note: candidate has non-matching type '[Decodable & PB]?'
error: type 'SA' does not conform to protocol 'Decodable'
note: cannot automatically synthesize 'Decodable' because '[Decodable & PB]?' does not conform to 'Decodable'
note: protocol requires property 'b' with type '[PB]?'; do you want to add a stub?
Note that the 4th line is non-sense: "'[Decodable & PB]?' does not conform to 'Decodable'". Wait what?
Any suggestion?

You may create a mixed protocol:
protocol PADecodable {
var b: [PB & Decodable]? { get }
}
struct SA: PADecodable {
let b: [PB & Decodable]?
}

you can fix it by:
protocol PA {
var b: [PB]? { get }
}
protocol PB {}
struct SA<T: PB & Codable>: PA, Codable {
private var _b: [T]?
var b: [PB]? {
return _b
}
}

Related

Difference between protocol combining typealias and empty conforming protocol

Is there a difference between these two in Swift?
protocol ABProtocol: AProtocol, BProtocol {}
typealias ABProtocol = AProtocol&BProtocol
To make things clearer, I will rename the second one to:
typealias ABProtocolIntersection = AProtocol & BProtocol
I can think of two differences off the top of my head.
If your type conform to AProtocol and BProtocol, the type is automatically a subtype of ABProtocolIntersection, but it does not automatically conform to ABProtocol. After all, ABProtocol is a totally different protocol.
Example:
class Foo: AProtocol, BProtocol { ... }
func foo<T: ABProtocolIntersection>(type: T.Type) { }
func bar<T: ABProtocol>(type: T.Type) { }
foo(type: Foo.self) // works
bar(type: Foo.self) // error
Another difference is that you can put extensions on ABProtocol, but not ABProtocolIntersection:
extension ABProtocol { } // OK
extension ABProtocolExtension { } // error
This is because ABProtocolIntersection is a non-nominal type, similar to types like (Int, Int) or (Int) -> String. See also: What is a 'non-nominal type' in Swift?
Yes there is a difference. The former defines a new protocol to which types must conform when it is used. The latter only defines a "placeholder" for AProtocol&BProtocol
Consider the following code:
protocol AProtocol{}
protocol BProtocol{}
protocol ABProtocol1: AProtocol, BProtocol {}
typealias ABProtocol2 = AProtocol & BProtocol
func f1(value: ABProtocol1) {}
func f2(value: ABProtocol2) {}
Arguments to f1 must conform to ABProtocol1 but arguments to f2 can conform to AProtocol and BProtocol. You do not need to explicitly conform types to ABProtocol2. For example:
struct A: AProtocol, BProtocol
{
}
f1(value: A()) // Error!
f2(value: A()) // OK

Protocol restriction on another protocol associated type

I have a protocol MyProtocol which has an associatedtype, inferred by the return type of myFunction
struct MyStruct: Codable {
var myVar: Int
}
protocol MyProtocol {
associatedtype MyType
func myFunction()-> MyType
}
class MyClass1: MyProtocol {
func myFunction()-> MyStruct? {
return MyStruct(myVar: 1) //ex.
}
}
class MyClass2: MyProtocol {
func myFunction()-> Int? {
return 1 // ex.
}
}
In MyClass1, associatedtype is infered as MyStruct?
In MyClass2, associatedtype is infered as Int?
from there everything works fine. No I want to build another protocol that can only be applied to a MyProtocol if associatedtype is Codable :
protocol MyProtocolCodable where Self: MyProtocol, MyType == Codable? {}
the code runs fine until here but when I try to apply it to my class I get an error:
extension MyClass1: MyProtocolCodable{} 🛑
'MyProtocolCodable' requires the types 'MyStruct?' and 'Codable?' (aka 'Optional<Decodable & Encodable>') be equivalent
yet, as far as I can see MyStruct? (aka Optional) and Codable? (aka Optional<Decodable & Encodable>) are equivalent?
How can I get rid of this error message? Am I doing something that is not meant to be done?
As far as I can see MyStruct? (aka Optional) and Codable? (aka
Optional<Decodable & Encodable>) are equivalent?
No, they are not. MyStruct conforms to Codable but is not equivalent of it.
As in: every MyStruct is Codable but not every Codable is MyStruct.
You can try changing MyType == Codable? to MyType: Codable:
protocol MyProtocolCodable where Self: MyProtocol, MyType: Codable {}
as MyStruct is not equal to Codable?.

Class-only protocol as typealias for associatedtype with AnyObject constraints

In Swift 4.0 I could write something like this
protocol ObserversHolder {
///Compiling Error in Swift 4.1
///note: possibly intended match 'StringManager.ObserverValue' (aka 'StringObserver') does not conform to 'AnyObject'
///note: protocol requires nested type 'ObserverValue'; do you want to add it?
associatedtype ObserverValue: AnyObject
var observers: [ObserverValue] {get set}
}
protocol StringObserver: class {
func showString()
}
class StringManager: ObserversHolder {
typealias ObserverValue = StringObserver
var observers = [ObserverValue]()
}
But in Swift 4.1 I receive the error Type 'StringManager' does not conform to protocol 'ObserversHolder'.
Is it possible to resolve this?
Change AnyObject to Any
protocol ObserversHolder {
///Compiling Error in Swift 4.1
///note: possibly intended match 'StringManager.ObserverValue' (aka 'StringObserver') does not conform to 'AnyObject'
///note: protocol requires nested type 'ObserverValue'; do you want to add it?
associatedtype ObserverValue: Any
var observers: [ObserverValue] {get set}
}
protocol StringObserver: class {
func showString()
}
class StringManager: ObserversHolder {
typealias ObserverValue = StringObserver
var observers = [ObserverValue]()
}

How do you structure generic type protocol conformance in Swift?

The following contrived Swift 2 example from real-world code won't compile:
protocol SomeModelType { }
protocol SomeProtocol {
var someVar: SomeModelType? { get }
}
class ConcreteClass<T: SomeModelType>: SomeProtocol {
var someVar: T?
}
This doesn't make sense to me fully. I would assume in ConcreteClass that because I have T being constrained to SomeModelType and have T as the backing type for the someVar property, the compiler would be able to figure out that the SomeProtocol was being conformed to by ConcreteClass.
How should an example like this be structured? Is it possible to the Swift compiler to determine protocol conformance through generic type constraints?
protocol SomeModelType { }
protocol SomeProtocol {
associatedtype T: Any
var someVar: T? { get }
}
class ConcreteClass<T> :SomeProtocol where T: SomeModelType {
var someVar: T?
}

Swift: type does not conform to protocol

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!