I want to have a generic factory method where I create a specific subclass depending on what the generic type parameter is. I've had a hard time working out how to approach it, and my current angle isn't working.
Below is a simplified version of what I have. The full version is in this gist, and the previous working version of the file is here. Basically I have a generic sequence and iterator where I want the type parameter to be a more abstract type, and doing so comes down to solving this factory puzzle. Any suggestions?
protocol Branch {}
protocol LocalBranch: Branch {}
protocol RemoteBranch: Branch {}
// Here's the concrete type, where I need to store a pointer (from libgit2).
// The factory will know about the pointer situation,
// but it's not part of the protocol interface.
class GitBranch: Branch
{
let pointer: OpaquePointer
init(pointer: OpaquePointer)
{
self.pointer = pointer
}
}
class GitLocalBranch: GitBranch, LocalBranch {}
class GitRemoteBranch: GitBranch, RemoteBranch {}
class BranchIterator<BranchType: Branch>: IteratorProtocol
{
public func next() -> BranchType?
{
let pointer = OpaquePointer(bitPattern: 0) // figure out a real value
return makeBranch(pointer)
}
// I expected this to get overridden by what's in the extension
fileprivate func makeBranch(_ pointer: OpaquePointer?) -> BranchType?
{
print("oops")
return nil
}
}
/* Same-type constraint type 'LocalBranch' does not conform to required protocol 'Branch'
extension BranchIterator where BranchType == LocalBranch {}
*/
extension BranchIterator where BranchType: LocalBranch
{
fileprivate func makeBranch(_ pointer: OpaquePointer) -> BranchType?
{
print("made local branch")
return GitLocalBranch(pointer: pointer) as? BranchType
}
}
// ...and similarly for remote branch
let localIterator: BranchIterator<GitLocalBranch> = BranchIterator()
let branch = localIterator.next()
// output: "oops"