0

I'm trying to write a static generic method which takes a protocol as an argument and register class instance in Swinject container as a protocol resolve. It's important that I could not register a module as a protocol it does not conforms to.

I wrote something like this:

/// RegisterableModule guarantee that conformer has `create()` method returning self

public extension RegisterableModule {

    static func registerModule<P>(asProtocol proto: P.Type,
                                  in container: Container) {
        container.register(proto, name: nil) { (resolver) -> P in
            return self.create()
        }
    }
}

It does not compile because obviously Self may be not conforming to P

I also tried to specify generic constraint using where:

  1. where Self: P does compile error "Type 'Self' constrained to non-protocol, non-class type 'P'"
  2. where self: P does multiple compiles error.
  3. where Self: P.Type does compile error "Type 'Self' constrained to non-protocol, non-class type 'P.Type'"
  4. where self: P.Type does multiple compile errors.

I also wonder if I can specify a constraint that P can be protocol only.

Vladlex
  • 845
  • 8
  • 16

2 Answers2

1

Unfortunatelly, there is no way (yet) in Swift to define requirement of conformance to generic parameters, or require parameter to be a protocol.

This is the reason why Swinject's type-forwarding API is not type safe. There is a "trick" that sort-of enables one to express a conformance requirement, however I'm not sure if it would be practical for your use-case:

extension RegisterableModule {

    static func registerModule<P>(
        asProtocol proto: P.Type, 
        in container: Container, 
        typeCheck: (Self) -> P
    ) {
        container.register(proto) { _ in self.create() as! P }
    }
}

MyModule.registerModule(
    asProtocol: MyProtocol.self, 
    in: container, 
    typeCheck: { $0 }
)
Jakub Vano
  • 3,833
  • 15
  • 29
  • (yet)? Is there any rumor about "generic parameters as constraints?" :) Only thing that I can found is two Jira issues: https://bugs.swift.org/browse/SR-5400 https://bugs.swift.org/browse/SR-5213 – Tolga Okur Feb 23 '19 at 17:14
  • @TolgaOkur Not that I know of. It is just me being a bit optimistic :) – Jakub Vano Feb 25 '19 at 08:04
0

Can you try it, I just added P:SomeProtocol

public extension RegisterableModule {

    static func registerModule<P:SomeProtocol>(asProtocol proto: P.Type,
                                  in container: Container) {
        container.register(proto, name: nil) { (resolver) -> P in
            return self.create()
        }
    }
}
  • I don't have SomeProtocol. What swift version do you use? – Vladlex Feb 22 '19 at 10:50
  • SomeProtocol is any custom type that you can create, I only created for illustration purpose. Here I am constraining the P so that it can only accept the types that conform to SomeProtocol. – Ipy Creator Feb 25 '19 at 06:54
  • But I want this one should be a protocol. No matter what exactly, but protocol, not a class which is conforming protocol. There should be no way to pass `MyClass: AnyProtocol` as a proto because MyClass is not a Protocol, it's a class which is conforming protocol. – Vladlex Mar 14 '19 at 10:42