1

This code fails to compile with Swift 5.1

import Foundation

protocol SomeClassProtocol: AnyObject {}
class SomeClass: SomeClassProtocol {}

class GenericClass<T:AnyObject> {
    weak var t: T?
    init(t: T) {
        self.t = t
    }
}

let test = GenericClass<SomeClassProtocol>(t: SomeClass())

The error is

'GenericClass' requires that 'SomeClassProtocol' be a class type

Does the compiler really need a class type here instead of a class-only protocol?

Ruben
  • 1,950
  • 1
  • 12
  • 13
  • I believe you're encountering the same problem as this thread: https://stackoverflow.com/questions/24888560/usage-of-protocols-as-array-types-and-function-parameters-in-swift - in short, not all `protocol` types can be used as generic type arguments. – Dai Mar 12 '20 at 05:45

3 Answers3

0

Yes. Though the syntax is the same (a colon), protocol inheritance is not the same thing as protocol conformance. Protocols do not conform to protocols; only types can conform to protocols. (AnyObject is not special in this regard; your question is good but the title isn't getting at the issue.)

In your example: Your T needs to conform to AnyObject. SomeClassProtocol does not conform to AnyObject. But any types that conform to SomeClassProtocol will conform to AnyObject.

So you need to pick which of these you really want:

    1.
let test = GenericClass( t: SomeClass() )

(test is a GenericClass<SomeClass>.)

    2.
class Class {
  weak var object: AnyObject?
  init(object: AnyObject) {
    self.object = object
  }
}

Class( object: SomeClass() )

You do have the option of subclassing, if that would be useful.

class GenericClass<T: AnyObject>: Class {
  var t: T? {
    get { object as? T }
    set { object = newValue }
  }
}
  • Why does protocol-inheritance not imply or assert that a protocol conforms to another protocol? In other languages like Java and C# then if you have `interface IFoo : IBar` then `IBar` is covariant with `IFoo`, but in Swift if you have `protocol Fooable : Barable` you cannot substitute in a `Fooable` value where a `Barable`-typed parameter argument is expected. – Dai Mar 12 '20 at 12:06
0

Does the compiler really need a class type here instead of a class-only protocol?

Yes, it does. I think the problem is just understanding what this means:

class GenericClass<T:AnyObject>

That means: "To resolve GenericClass, the parameterized type T must be some type that is a class." Examples would be UIView, NSString, etc.

Okay, so:

let test = GenericClass<SomeClassProtocol>(t: SomeClass())

So, SomeClassProtocol is none of those; it isn't the name of a class. It's the name of a protocol.

A further difficulty may be understanding protocols as types. They are not really full-fledged types.

matt
  • 515,959
  • 87
  • 875
  • 1,141
-2

You don't need to specify T explicitly.

Change your code from this:

let test = GenericClass<SomeClassProtocol>(t: SomeClass())

To this:

let test = GenericClass(t: SomeClass())
Rob C
  • 4,877
  • 1
  • 11
  • 24