I have a type for a Vector, where I implement a version for Double and a version for Float.
protocol Vector {
associatedtype ScalarType: BinaryFloatingPoint
var a: ScalarType
var b: ScalarType
var c: ScalarType
}
struct Float3: Vector {
typealias ScalarType = Float
var a: Float
var b: Float
var c: Float
}
struct Double3: Vector { /* . . . */ }
Additional functionality is provided using protocols. For example I have a protocol for computing a dot product that may or may not be implemented by the Vector type.
protocol DotProduct {
func dot(_ other: Self) -> ScalarType
}
In some other area of the codebase, I implement another type that uses the Vector as an associated type. For example, a triangle...
struct Triangle<T: Vector> {
var a: T
var b: T
var c: T
}
I implement various extensions that are available if the Vector type implements certain protocols. For example, compute the barycentric coordinates if the underlying vector type supports dot product.
extension Triangle: Barycentric where VectorType: DotProduct {
func barycentricCoordinates(for position: VectorType) -> (u: VectorType.ScalarType, v: VectorType.ScalarType, w: VectorType.ScalarType)?
}
Somewhere else in my code, I implement a function that extends Triangle to add a convenience function that calls the barycentricCoordinates
function.
extension Triangle: TestPosition {
func positionIsInsideTriangle(_ position: VectorType) -> Bool {
barycentricCoordinates(for: position) != nil
}
}
Sadly, this hits a compilation error, as TestPosition
is dependent on Barycentric
conformance which is only exists if the associated vector type conforms to DotProduct
.
This can be solved by adding a conformance requirement to the extension:
extension Triangle: TestPosition where VectorType: DotProduct { /* . . . */ }
However, this requires that TestPosition knows enough about the implementation of the Barycentric extension to know its requirements. Additionally, if the requirements for Barycentric conformance are changed, multiple places will need updating. In some cases, this is more than a single conformance.
In reality all I really care about is whether Triangle conforms to Barycentric or not.
I'd hope I could do something like this:
extension Triangle: TestPosition where Triangle: Barycentric { /* . . . */ }
But that also doesn't work.
Am I missing something obvious here? Is there a way to extend a type if it also conforms to another protocol?
Thanks!