I was trying to provide different implementations for a struct if its generic type is satisfied with different conditions.
Here is a demo example to illustrate my problem:
public protocol FooProtocol {
/// `Bar` is my own type, using `String` here for demo purpose
typealias Bar = String
func to() -> [Bar]
init?<C: Collection>(collection: C) where C == C.SubSequence, C.Element == Bar
}
public struct Foo<Value> {
let value: Value
}
extension Foo: FooProtocol where Value: Numeric {
public func to() -> [Bar] {
return ["\(self.value)"]
}
public init?<C: Collection>(collection: C) where C == C.SubSequence, C.Element == Bar {
return nil
}
}
extension Foo where Value: RangeReplaceableCollection, Value.Element: FooProtocol {
public func to() -> [Bar] {
return self.value.reduce(into: []) { $0 += $1.to() }
}
public init?<C: Collection>(collection: C) where C == C.SubSequence, C.Element == Bar {
self.value = .init()
}
}
And when I do following:
let intFoo: Foo<Int> = .init(value: .max) /// give me instance of Foo<Int>
let intTo = intFoo.to() /// give me value of ["9223372036854775807"]
let intBack = Foo<Int>(collection: intTo)?.value
/// Should give me `nil`, however...
/// error: expression type 'Foo<Int>?' is ambiguous without more context
So why is the ambiguity? The generic type is Int
, which means it should use the initializer in the first extension where the Value
is a Numeric
, unless the Int
is actually a RangeReplaceableCollection
at the same time?