Cannot use class-only protocols as type parameters on swift

When I try to do the following (I tried to make sure the names make sense of what I wanna do):


/*
*  Base
*/
protocol BaseDepartment: class {
func headCount()->Int
}
class Employee<DepInterface: BaseDepartment> {
weak var department: DepInterface?
}
/*
*  Actual
*/
protocol DevDepartment: class, BaseDepartment {
func devLanguages() -> [String]
}
class Developer: Employee <DevDepartment> {

}


I get the following error:


Playground execution failed: /var/folders/04/br_2sh2n5cb2f84b7bl8pc6h0000gp/T/./lldb/56957/playground208.swift:21:18: error: using 'DevDepartment' as a concrete type conforming to protocol 'BaseDepartment' is not supported


Could you please help me fix this? Basically, I need to be able to pass protocols as type parameters in a generic. It works well for classes, but not for protocols!


Thanks a lot

As described in the error message, currently in Swift:

using some protocol as a concrete type conforming to a protocol (including the subject protocol itself) is not supported


This compiles, but the behavior may very probably not be as you expect:

class Developer<T: DevDepartment>: Employee<T> {
  
}


What I can think of now is making the DevDepartment an abstract (conceptual, Swift does not have `abstract`) class, which you may already know:

class DevDepartment: BaseDepartment {
    func headCount() -> Int {
        fatalError("Concrete subclasses should override this method")
    }
    func devLanguages() -> [String] {
        fatalError("Concrete subclasses should override this method")
    }
}
class Developer: Employee <DevDepartment> {
    //...
}

I think it is important to think through your design up front otherwise the path forward may be very difficult. Generics are really useful for working with objects of a single concrete type. So in your example, if you are going to be working with Developer instances directly then Generics may be the way to go. However, if you intend to work with a mixture of Employee subclasses (e.g. an array of employees of arbitrary Employee subtypes) then Generics may prove to be problematic for this example.

Don't use generics - protocols in Swift are full types (as long as they don't require associated types, which yours don't). Define your variables as being of type BaseDepartment. If you need to check for other protocol conformances or a specific concrete type, you can use the "is" or "as?" keywords.


The generics system right now really isn't very useful. Use protocols as far as you can, and for the love of god avoid adding typealiases and making generic protocols - at some point in your code, you will get to a point where the type system will stop your progress. At that point, you may have written a lot of code. You don't want to have to maintain type-erased wrappers just so you can escape back to non-generic-protocol land.

Have you considered just using protocols instead of class inheritance. Protocols have the advantage that you get flexibility to provide storage for the specific type while still supporting abstract usage.


For example, you might try something like the following:

protocol Department {
  var headCount : Int { get }
}
protocol DevDepartment : class, Department {
  var devLanguages : [String] { get }
}
protocol Employee {
  var department: Department? { get }
}
class Developer: Employee {
  var department : Department? {
  return devDepartment
  }
  weak var devDepartment : DevDepartment?
}

In this example, you only store the real department (DevDepartment) in this case, but you can still reference it via the department property when needed in the abstract sense and devDepartment when you really want to work with the employee as a Developer. You could throw a Developer instance into collections of both employees and developers.

This issue seems like a compiler bug to me. The behavior seems to be that you can use a protocol to satisify a Generic type unless there is a protocol constaint on that type in which case only a concrete type can satisfy it. The compiler seems (in this use case) to be treating a protocol inherited from a base protocol as not conforming to that base protocol. If you remove the type constraint then all is well. Why can't a protocol satisfy a type constraint if it inherits from the constraining protocol?


Can someone remark whether this is really the intended behavior?

I wonder too if this is an intended change in Swift 2. This worked in Swift 1.2, but no longer compiles in Swift 2.


class Subscription<T: AnyObject> {
     weak var subscriber: T?
}
class Subscribe<T: AnyObject> {
    var subscriptions: [Subscription<T>]
}
protocol MyProtocol: class {
}
var s: Subscribe<MyProtocol>
Cannot use class-only protocols as type parameters on swift
 
 
Q