Mark Mark - 2 months ago 25
Swift Question

Swift generic reference type

I'm having issues trying to constrain generic type requirements to just reference types. Here's some example code:

class WeakHolder<Element: AnyObject> {
weak var element: Element?

init(element: Element) {
self.element = element

protocol Animal: class { }

class Dog: Animal { }

let dog: Animal = Dog()
let holder = WeakHolder<Animal>(element: dog) // Error: Using "Animal" as a concrete type conforming to protocol 'AnyObject' is not supported.

If I change the generic requirement to
<Element: class>
, I get the error
class constraint can only appear on protocol declarations

Is this a limitation of generics? Marking a protocol as class is enough to have a weak reference to that protocol, is there no equivalent in generics?


The simple answer is that you cannot have a generic type that is a protocol.

Writing out the syntax makes it clear how this works: class/struct GenericType<TypeName: TypeConstraints> {}

let thing = GenericType<Type>() where Type is a class or struct that adheres to any constraints

A Protocol Requiring adopting Types to be a class means any adopters are classes, but the Protocol itself is still not a Type.

It's possible generics could at some point support protocols, but it would require changing the general approach to either protocols or generics. Though your specific example may be possible with a smaller amount of work behind the scenes, so it's possible this may be implemented at some point.

You can take a look at The Generics Manifesto if you want to see the direction they're going. Skimming it I didn't find anything directly related to your use case, but it's fairly specific so it may not be included in the parameters of the document.