So I was wondering if any one could explain the rational behind this error or an explanation of what I am doing wrong.
I am trying to create a generic function which takes a protocol constrained type which has a static method on it called solve.
But for some reason even though it resolves the constraint fine in Xcode the compiler throws a hissy.
Is there any reason it shouldn't be able to infer a type which I am already specifying or is there a naive error in my code sample?
Edit: As it wasnt explicit enough
I know how to work around it, I was just curious for an explanation of why static members in interfaces/ protocols are problematic.
protocol NodeSolver {
static func solve(_ nodes: [Node]) -> [Node]
}
func findPath<T: NodeSolver>(nodes: [Node]) -> [Node] {
return T.solve(nodes)
}
Since it seems you want findPath
to be a method strongly connected to the type that conforms to NodeSolver
, but wont use any instance of this concrete NodeSolver
type in the findPath
method itself, you might want to consider simply adding the general findPath
method as a type method available by a default implementation for all types conforming to NodeSolver
.
E.g.:
struct Node {}
protocol NodeSolver {
static func solve(_ nodes: [Node]) -> [Node]
static func findPath(nodes: [Node]) -> [Node]
}
extension NodeSolver {
static func findPath(nodes: [Node]) -> [Node] {
// hopefully some more logic ...
return Self.solve(nodes)
}
}
struct MyNodeSolver: NodeSolver {
// dummy solver
static func solve(_ nodes: [Node]) -> [Node] {
return nodes
}
}
let myNodes = [Node(), Node()]
// make use of the default implementation of `findPath` available
// to all types conforming to 'NodeSolver': this method itself
// make use of the concrete type-specific implementation of 'solve'
// in the types conforming to 'NodeSolver'.
let dummyPath = MyNodeSolver.findPath(nodes: myNodes)
I am handing a constrained type in the protocol I am specifying. And the actual type in the method call.
findPath<NodeSolver1>(nodes) findPath<NodeSolver2>(nodes)
Another workaround, possible closer to what you're trying to achieve, is to wrap the generic function into a generic type (say, struct
) which holds a non-generic function findPath
w.r.t. concrete versions of the generic type. If viewing the wrapped findPath
from a viewpoint external to the owning type, the functions is generic w.r.t. the generic typeholder of the owning type.
E.g.:
struct Node {}
protocol NodeSolver {
static func solve(_ nodes: [Node]) -> [Node]
}
struct NodeSolverA: NodeSolver {
static func solve(_ nodes: [Node]) -> [Node] {
return nodes
}
}
struct NodeSolverB: NodeSolver {
static func solve(_ nodes: [Node]) -> [Node] {
return nodes.reversed()
}
}
// instead of a generic function, wrap a concrete function
// in a generic type
struct AnyNodeSolver<T: NodeSolver> {
static func findPath(nodes: [Node]) -> [Node] {
return T.solve(nodes)
}
}
let myNodes = [Node(), Node()]
let dummyPathA = AnyNodeSolver<NodeSolverA>.findPath(nodes: myNodes)
let dummyPathB = AnyNodeSolver<NodeSolverB>.findPath(nodes: myNodes)