I noticed that in Swift 2.2, if I have a protocol A, and then a protocol B: A which inherits from A, checking for conformance to the parent protocol like this fails: if objectConformingToBWhichInheritsFromA is A evaluates to false, as does the as? variant.
Am I doing something wrong?
My Playground tells a different story
protocol A { }
protocol B: A { }
class Foo: B { }
let foo = Foo()
foo is A // true
foo is B // true
Related
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.
protocol A {}
protocol B: A {}
protocol C {
var X: A { get }
}
struct D: C {
let X: B // ERROR: does not conform to protocol "C"
}
Shouldn't this be okay since B conforms with A?
I tried to remedy it by using an associatedtype in protocol C:
protocol A {}
protocol B: A {}
protocol C {
associatedtype SomeType: A
var X: SomeType { get }
}
struct D: C {
let X: B // ERROR: does not conform to protocol C -- seemingly requiring a concrete type
}
The error makes sense if you think about it the following way.
/// It does not have any requirements
protocol A {}
/// It has to satisfy all of the requirements of A (whatever they are)
/// It does not have any of it's own requirements (currently)
/// It is expected to add some additional requirements of it's own
/// Otherwise it defeats the purpose of having this
protocol B: A {}
/// This has only one requirement, X that conforms to A
protocol C {
var X: A { get }
}
/// This has only one requirement, X that conforms to B
/// The problem here is
/// - A & B are different and can not be used interchangeably
/// (at least in the current versions)
struct D: C {
let X: B // ERROR: does not conform to protocol "C"
}
Logically it makes sense - that B has to satisfy all requirements of A and hence it should be allowed.
I think Swift Forums might be a better place for discussing this.
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
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.
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