[swift-evolution] [Manifesto] Completing Generics

Brent Royal-Gordon brent at architechies.com
Wed Aug 3 04:09:50 CDT 2016


> On Aug 2, 2016, at 7:58 AM, Patrick Lind via swift-evolution <swift-evolution at swift.org> wrote:
> 
> http://stackoverflow.com/questions/38619660/is-it-possible-to-pass-generic-protocols-into-a-constructor-for-proper-dependenc

I *think* that the specific feature you're looking for here is usually called "enhanced existentials". This would have a different syntax—something like `RepositoryProtocol where Object == Zombie`—but would do basically the same thing.

The way to work around this in Swift 2 or 3 is to manually write a type-erasing wrapper:

	// Effectively a constructor of AnyRepository.
	public func anyRepository<Repository: RepositoryProtocol>(_ repository: Repository) -> AnyRepository<Repository.Object> {
		// Don't double-wrap
		if let repo = repository as? AnyRepository<Repository.Object> {
			return repo
		}
		return ConcreteAnyRepository(repository: repository)
	}
	
	// This is the public face of the wrapper. It's actually abstract. Since it doesn't have the 
	// RepositoryProtocol as a parameter, it "erases" the repository's type.
	public class AnyRepository<Object>: RepositoryProtocol {
		private init() {}
		
		public var items: Array<Object> {
			get { fatalError("abstract") }
			set { fatalError("abstract") }
		}
		
		public func insert(_ object: Object) {
			fatalError("abstract")
		}
		
		public func deleteAll() {
			fatalError("abstract")
		}
	}
	
	// All instances of AnyRepository will actually belong to this concrete subclass, which 
	// *does* have the specific RepositoryProtocol as a parameter.
	private class ConcreteAnyRepository<Repository: RepositoryProtocol>: AnyRepository<Repository.Object> {
		private let repository: Repository
		
		override var items: Array<Object> {
			get { return repository.items }
			set { repository.items = newValue }
		}
		
		override func insert(_ object: Object) {
			repository.insert(object)
		}
		
		override func deleteAll() {
			repository.deleteAll()
		}
	}

And then your ZombieServiceProtocol can look like:

	protocol ZombieServiceProtocol {
	    func fetchZombies()
	
	    var zombieRepository: AnyRepository<Zombie> { get set }
	}

-- 
Brent Royal-Gordon
Architechies



More information about the swift-evolution mailing list