generic class as associated type - swift

when I do:
class GenericClass<T> {}
protocol Protocol {
associatedtype A
associatedtype C : GenericClass<A>
}
class IntClass : GenericClass<Int> {}
struct Adopter : Protocol {
typealias A = Int
typealias C = IntClass
}
everything is ok 😎
but if I add a method to Protocol that uses the C associated type:
protocol Protocol {
...
func f(c: C)
}
and implement it in Adopter:
struct Adopter : Protocol {
...
func f(c: C) {}
}
everything brakes! The compiler tells me:
"Protocol requires function 'use(c:)' with type '(Adopter.C) -> ()'..."
My best guess is that this has something to do with the fact that C is a class and that the type signature f(c: C) would allow subclasses of C being passed but I can't see how that would be a problem...
Here's a gist illustrating the problem that you can paste into a playground
I'm wondering if this is a bug? I hope I'm not *again* fundamentally misunderstanding something with the type system 😅
update
I think I am getting to the root of the problem by just declaring the protocol like this:
protocol Protocol {
associatedtype A
associatedtype C : GenericClass<A>
func f(c: C)
}
putting this into a playground, I get the error:
Playground execution failed: error: generic parameter 'C' cannot be a subclass of both 'GenericClass<<< error type >>>' and 'GenericClass'
just because, I tried mimicking a similar type relationship with a struct:
struct Struct<
A,
C : GenericClass<A>
> {
func f(c: C) {}
}
This compiles just fine.

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

How to write generic constraint for optional type in Swift?

Once I write a generic constraint, it only fit the normal type, but not optional type. It will lead to a compiler error while I call it as optional type: Type 'SomeType? does not conform to protocol SomeProtocol'.
Here is the sample code:
protocol P {}
class C<T> {}
extension C where T: P {
static func test() {}
}
extension Int: P {} // OK
C<Int>.test() // OK
extension Int?: P {} // Fail, but I need it
C<Int?>.test() // Fail, but I need it
Updated:
I find a way to solve it.
Here is the sample code.
protocol P {}
class C<T> {}
extension C where T: P {
static func test() {}
}
extension Int: P {} // OK
C<Int>.test() // OK
protocol OptionalProtocol {
associatedtype WrappedType
}
extension Optional: OptionalProtocol {
typealias WrappedType = Wrapped
}
extension C where T: OptionalProtocol, T.WrappedType==Int {
static func test() {}
}
C<Int?>.test() // OK now
It's currently not possible to do this.
extension Optional: P where Wrapped == Int {}
If we try to extend Optional where Wrapped is constrained to an Int the compiler will complain that "extensions with constraints cannot have inheritance clauses".
Note: This is currently being worked on under the SE-0143 proposal and should arrive in a future version of Swift.

Re-conforming to a protocol / conforming multiple times / overriding associated type

Given the following protocol with an associated type:
protocol P {
associatedtype T
func f(t: T)
}
And the class A that conforms to protocol P:
class A: P {
func f(t: String) {
print(t)
}
}
Is there any way to override the conformance to 'P' in a subclass 'B' so that we can change the associated type 'T' ?
class B: A, P { // Redundant conformance of 'B' to protocol 'P'
func f(t: Int) {
super.f("Hello")
print(2 * t)
}
}
Writing that B conforms to P is redundant and gives an error.
B would be conforming to the protocol twice, which isn't possible even without subclassing.
I can think of scenarios where such a feature might be useful. Are there any reasons why this shouldn't be possible to do?
Edit:
What I'm asking is if there is any way to have A be P<T> and B be P<U> even if B is a subclass of A, i.e. override the associated type.
Your subclass already inherits the adoption of the protocol from its superclass, so there is no need to override the conformance of protocol in a subclass.
Reason:
protocol P {
var name:String{get set}
}
class A:P {
var name:String = "Swift"
}
class B:A {
override var name:String{
get{
return "Hello"
}set{
}
}
}
After conforming class B to protocol P you should implement the properties and methods.In normal cases, compiler will warn you to add the
required methods and properties..
But If that happens in this case,there will be conflict in name with the overridden ones..So this should not happen.And so you will get compiler error as
Re-conforming to a protocol

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!

Protocol downcasting in Swift

I have the following situation where I have a generic protocol A that can have variants that inherit from it (e.g. B) and a class that implements a variant (C).
protocol A {}
protocol B: A {
var foo: String { get }
}
class C: B {
let foo: String = "foo"
}
Now, if I have an object of type A, but is actually a C, how can I get to stuff declared in B?
func foo() {
let c: A = C()
}
If I try to cast as in let b = c as B I get Cannot downcast from 'A' to non-#objc protocol type 'B'.
Your code looks good - the only problem is that the as operator requires objc compatibility. You can fix it by prefixing your protocols with the #objc attribute:
#objc protocol A {}
#objc protocol B: A {
var foo: String { get }
}
Unfortunately there's a downside on doing that: you lose the ability to use swift-specific features that are not available in objective C, such as enums, tuples, generics, etc.
More info here: Checking for Protocol Conformance