The following Swift code yields this error on the last line: Type 'E' does not inherit from 'C<Self>'
. Not sure what's going on here. Any clues would be appreciated.
class C<T> {}
protocol P {
typealias E : C<Self>
}
class A : P {
typealias E = C<A>
}
class S<U : P> {}
class C2<T> : S<A> {}
Update: I simplified the broken example. The old version (to which milos' answer refers) can be found in this question's edit history.
I have renamed your identifiers so I can think about them:
protocol P {
typealias E : C<Self>
}
class A : P {
typealias E = C1<Any>
}
class B : P {
typealias E = C2<Any>
}
class C<T> {}
class C1<T> : C<A> {}
class S<T, U : P> : C<T> {} // <-- mark!
class C2<T> : S<B, A> {}
This should eventually, and very nearly does, work out. In effect, what you want is:
class B : P {
typealias E = C<B> // which is what P requires (same with class A)
}
However, on the marked line, where you are defining class S
you are asking the compiler to check the type of U : P
and then pass B
as the concrete type to check. Unfortunately, at this point B
's conformance to P
is still unresolved (i.e. it is itself defined in terms of C2 : S : C
, which is where you are going with U : P
). Removing : P
in U : P
removes the error, though this may not be what you want. Then again, depending on what you want, there may be any number of solutions :)
EDIT
The following is in response to @igul222's much simplified code example. I still, think, however, that the compiler is simply returning a less then helpful error message, which is really caused by the recursive type definition. Consider, for example, if you define an enum
in terms of itself:
enum E {
case C(E) // error: recursive value type 'E' is not allowed
}
Now, this is probably also the problem with the following:
class C<T> {}
protocol P {
typealias E : C<Self>
var c: E { get }
}
final class A : P {
typealias E = C<A>
var c: E { return E() }
}
// --> error: type 'A' does not conform to protocol 'P'
// --> note: protocol requires property 'c' with type 'E'
// --> note: candidate has non-matching type 'E'
... neither does this work (a version of your gist):
class C<T> {}
protocol P {
typealias E : C<Self>
}
final class A : P {
typealias E = C<A>
}
class X<U : P> {}
X<A>() // --> error: type 'E' does not inherit from 'C<`Self`>'
... or this:
class C<T> {}
protocol P {
typealias E : C<Self>
}
final class A : P {
typealias E = C<A>
}
let a = A()
func f<T: P>(T) {}
f(a) // --> error: 'A' is not identical to '`Self`'
What the compiler seems to be saying is that Self
in C<Self>
is not yet A
, i.e. that A
is not yet itSelf
since to be A
it must conform to P
which is in turn pending C<Self>
checking out... But the following works because A
no longer defines an associated type in terms of itself:
class C<T> {}
protocol P {
var c: C<Self> { get }
}
final class A : P {
typealias E = C<A> // just a typealias, no longer an associated type
var c: E { return E() }
}
Some patterns of functional programming require recursively defined types, so it might be nice to have that in Swift. At present, however, I am not sure one can usefully conform to a protocol with an associated type of the form T<Self>
, even though the compiler allows its definition... otherwise, this should all just work at runtime.
EDIT 2
I have just upgraded to Xcode 6.1 GM Seed and things have changed! The following snippet, that would not have compiled before, now compiles and appears to run fine!
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
class Ca: A {
var b: B?
}
class Cb: B {
var a: A?
}
let a = Ca() // --> {nil}
let b = Cb() // --> {nil}
a.b = b // --> {{{...}}}
b.a = a // --> {{{...}}}
This improvement, however, does not extend to recursively defined associated types.