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

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?
}

Related

Swift Generics: Conforming to protocol by constraining generic parameters to variable types defined by said protocol

In my Domain module I am defining a protocol Assignment, TimeLog and AssignmentTimeLog.
When defining a concrete implementation I want to use generics to conform to the AssignmentTimeLog protocol. To do so I am constraining my generic A, T parameters to be of type Domain.Assignment and Domain.TimeLog. Why does this not satisfy the protocol requirements? I want to understand the logic of what's going on.
// Domain Module
public protocol AssignmentTimeLog {
var assignment: Assignment { get }
var timeLog: TimeLog { get }
}
// My attempt to create an implementation trows an error
// Error:
// Type 'AssignmentTimeLog<A, T>' does not conform to protocol 'AssignmentTimeLog'
import Domain
struct AssignmentTimeLog<A, T>:
Domain.AssignmentTimeLog where A: Domain.Assignment, T: Domain.TimeLog {
var assignment: A
var timeLog: T
}
For Context: The reason for using generics is that later I want to define an extension on AssignmentTimeLog where A & T also implement another protocol. This provides additional functionality without additional code. Concrete types implement the Domain protocols as well as those additional protocols.
I have tried to figure out this by reading the documentation and multiple blogs. But I can't seem to zone in on the exact issue/gap in understanding that I have.
The protocol says a different thing from what your implementation says.
Fact 1
According to the protocol this getter
var assignment: Assignment { get }
can return any value conforming to Assignment.
Fact 2
On the other hand your implementation here
var assignment: A
says that assignment will contain a value of a specific type A (which happens to conform to Assignment).
These are 2 very different statements.
The fix
Here's an easy fix
protocol AssignmentTimeLog {
associatedtype A: Assignment
associatedtype B: TimeLog
var assignment: A { get }
var timeLog: B { get }
}
struct MyAssignmentTimeLog<A, T>: AssignmentTimeLog where A: Assignment, T: TimeLog {
var assignment: A
var timeLog: T
}

Is it possible to declare a protocol with an associatedtype inside a protocol?

I want to declare a protocol with an associatedtype inside the protocol.
I know that declaring it as a class rather than a protocol solves the problem.
But I want to use it within the protocol.
Is there a way to use a protocol with an associated type in the protocol using things like generics or typealias?
protocol A {
associatedtype T
}
protocol B {
var a: A { get } // error. protocol 'A' can only be used as a generic constraint because it has Self or associated type requirements
// But I want set a.T = Int
}
If you really want to set A.T to Int, you can specify that in an associated type where clause within B:
protocol A {
associatedtype T
}
protocol B {
associatedtype U: A where U.T == Int
var a: U { get }
}
Or, you do not want to lock B to only one particular A.T type, you can introduce another associatedtype, which links back to A:
protocol A {
associatedtype T
}
protocol B {
associatedtype T
associatedtype U: A where U.T == T
var a: U { get }
}
See Associated Types with a Generic Where Clause in The Swift Programming Language.
protocol A {
associatedtype T
var a: T { get }
}
protocol B {
associatedtype U where U: A
var b: U { get }
}
Keep in mind though that you're gonna have to reason a lot about this because of the two associated types.

Why sub-protocol doesn't fulfill conformance for its parent? [duplicate]

This question already has answers here:
Why can't a get-only property requirement in a protocol be satisfied by a property which conforms?
(3 answers)
Closed 4 years ago.
I have structs that are conforming to protocols, but are using derived protocols, instead of directly using its parent protocol:
protocol A { }
protocol B: A { }
protocol C {
var property: A { get }
}
struct Foo: C {
let property: A
}
struct Bar: C {
let property: B
}
// Error: Type 'Bar' does not conform to protocol 'C'
Why doesn't Bar fulfill the conformance because property is a sub-protocol of A.
B describes a type that conforms to some set of rules. It is not itself a type that conforms to those rules. B does not conform to B, let alone anything it requires additional conformance to. protocol B:A says "anything that conforms to B also must conform to A." However, B does not conform to B, and so does not conform to A.
This has been answered many times on SO, but to repeat the "why," it comes down most simply to this example:
protocol A {
init()
}
func f(type: A.Type) {
let a = type.init()
}
f(type: A.self)
If A itself conforms to A, then this should be legal. But what init should f call? In the presence of init and static requirements, it's not possible for protocols to conform to themselves.
While the specific covariance you want in this case is possible in principle, Swift doesn't have the ability to distinguish between legal and illegal covariance, and disallows all of it. For example, consider the small variation from immutable to mutable:
protocol C {
var property: A { get set }
}
In this case, it is definitely impossible for Bar to conform (it would have to provide a setter for property that accepted any A, even though the getter would return a subtype of A). Swift is not able to distinguish all the cases where it is possible (generally when everything is immutable and there are no init or static requirements) from the cases where it isn't. There's been some discussion of allowing these kinds of cases where it's technically possible, but the concern is that very small changes to the protocol could then break your entire type structure, sometimes for non-obvious reasons. Instead, at least for now, type requirements are generally invariant.
A typical way to address this overall issue is to just provide accessors for the types you want. For example:
protocol A { }
protocol B: A { }
protocol C {
var aProperty: A { get }
}
struct Foo: C {
let aProperty: A
}
struct Bar: C {
var aProperty: A { return bProperty }
let bProperty: B
}
This provides greater flexibility (you can make bProperty a var if you like), and makes your code more explicit.

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!

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.