Consider a protocol P with an associated type Q,
protocol P {
typealias Q
init(_ q: Q)
func flatMap(f: Q -> Self) -> Self
// Composeable from init and flatMap
func map(f: Q -> Self.Q) -> Self
// ... There are many others
}and a conforming generic type C<T>, where T is constrained to Q
struct C<T> : P {
typealias Q = T
private let t: T
init(_ q: T) {
self.t = q
}
func flatMap<A>(f: Q -> C<A>) -> C<A> {
return f(t)
}
// Compose from init and flatMap
func map<A>(f: T -> A) -> C<A> {
return flatMap { C<A>(f($0)) }
}
}This works
let c1: C<Int> = C(42) // t = 42
let c2: C<String> = c1.map { "\($0) is the answer" } // t = "42 is the answer"With Swift 2.0, I'd expect to be able to use a protocol extension to share all combinators that can be composed from init and flatMap
extension P {
func map(f: Q -> Self.Q) -> Self {
return flatMap { Self(f($0)) }
}
}But, on removing the implementation of map in C—to expose the shared version in the extension—this is the result
let c1: C<Int> = C(42)
let c2: C<String> = c1.map { "\($0) is the answer" }
// error: cannot invoke 'map' with an argument list of type '((_) -> _)'In the case of C, the compiler was able to connect Self.Q and Self with A and C<A> respectively, whereas in the extension the compiler seems to link Self.Q and Q to the conforming type itself.
Question 1. Is this the expected behaviour?
Question 2. Should there not be a way to restrict the various uses of Self through the associated type, e.g. Self<Q == A> or something similar—this syntax was suggested by someone else some time ago . Here's the way I would have liked to have approached this example.
protocol P {
typealias Q
init(_ q: Q)
func flatMap<A>(f: Q -> Self<Q == A>) -> Self<Q == A>
// Composeable from init and flatMap
func map<A>(f: Q -> A) -> Self<Q == A>
}
extension P {
func map<A>(f: Q -> A) -> Self<Q == A> {
return flatMap { Self<Q == A>(f($0)) } // Inferrable?
}
}
struct C<T> : P {
typealias Q = T
private let t: T
init(_ q: T) {
self.t = q
}
func flatMap<A>(f: Q -> C<A>) -> C<A> {
return f(t)
}
}Although there has been some discussion in the past, I thought it should be raised again, given the protocol extension capability. Of course, such an approach may have other undesireable implications.
Looking forward to hearing opinions.