13

Given we have a Swift protocol with one static method:

protocol Creatable: class {
    static func create() -> AnyObject
}

and a pure Swift class which conforms to the protocol:

class Foo : Creatable {
    static func create() -> AnyObject {
        return Foo() as AnyObject
    }
}

Later on when one tries to make use of that protocol by operating on type Creatable e.g.:

var f : Creatable = Foo.self
f.create()

The compiler complains with the following:

error: type 'Foo.Type' does not conform to protocol 'Creatable'

The question is: is this a Swift limitation or I'm using the protocols and static/class method in the wrong way.

Objective-C equivalent would be something like:

Class someClass = [Foo class];
if ([someClass conformsToProtocol:@protocol(Creatable)]) {
    [(Class <Foo>)someClass create];
}
Floern
  • 33,559
  • 24
  • 104
  • 119

2 Answers2

9

A Creatable reference points to an instance of Foo, not to the Foo type itself.

To get the equivalent of the class-level protocol implementation, you need an instance of Creatable.Type:

let c: Creatable.Type = Foo.self

However, you’ll get an error when you then try to use it:

// error: accessing members of protocol type value 'Creatable.Type' is unimplemented
c.create()

All that said, is there a reason why you can’t just use functions to fulfill your requirement, instead of metatypes?

let f = Foo.create
// f is now a function, ()->AnyObject, that creates Foos
let someFoo = f()
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • Thanks for you answer. The reason I try to work with meta types is that I'm working on a factory of objects. Ideally I would create an new instance out of the type itself. But as I found it's not possible with the Swift's strong typing architecture. As a workaround I thought about using the protocol with static method approach. This way I could collect meta types which conform to the protocol and create objects. Maybe I am mistaken and there's a better way of creating factory. – Aleksander Zubala Mar 11 '15 at 08:41
  • "Ideally I would create an new instance out of the type itself. But as I found it's not possible with the Swift's strong typing architecture.” You mean, you have an instance, and you want to clone it? Swift’s type system has a number of ways to do this. – Airspeed Velocity Mar 11 '15 at 11:13
  • I would like to achieve a standard factory with an API which accepts type as parameter and returns the object. The problem is with defining such method, the input parameter has to be generic type. I've tried to use generics, with type constraint: `create(type :T)` , but it complains that the static methods is not visible. – Aleksander Zubala Mar 11 '15 at 12:24
  • 2
    The following code ought to work. However, there is probably a better way of solving your problem than the way you are trying to get working, abstract factories are more useful in languages that don't have a good generic implementation and first-class functions in the first place. `protocol Creatable { static func create() -> AnyObject }; func create(type: T.Type) -> AnyObject { return T.create() };class S: Creatable { static func create() -> AnyObject { return S() } };let s = create(S.self)` – Airspeed Velocity Mar 11 '15 at 13:32
  • Thanks I will give it a thought. Meanwhile your suggestion for generic function parameter: `type: T.Type` did what I expected. Thanks for the help! – Aleksander Zubala Mar 13 '15 at 20:31
8

Using .Type is the key:

var f : Creatable.Type = Foo.self

And this no longer gives the "unimplemented" error. See full code below:

protocol Creatable: class {
    static func create() -> AnyObject
}

class Foo : Creatable {
    static func create() -> AnyObject {
        return Foo() as AnyObject
    }
}

var f : Creatable.Type = Foo.self
f.create()
Jerry
  • 4,382
  • 2
  • 35
  • 29