Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call a generic function with a dynamic type in Swift

Tags:

generics

swift

Say I have a protocol Fooable:

protocol Fooable {}

Now I need to work with a Fooable type in a generic function:

func fooingAround<FooableType: Fooable>(withType: FooableType.Type) {}

This works fine when I just call the function with a Fooable type:

struct Foo: Fooable {}
fooingAround(Foo.self) // works fine

However, I need to retrieve the Fooable type that I hand over to the function from somewhere else. This is where the compiler fails:

let fooableType: Fooable.Type = // obtain from somewhere else
fooingAround(fooableType) // compiler error: "Cannot invoke 'fooingAround' with an argument list of type '(Fooable.Type)'"

Specifically, I obtain the Fooable.Type from an enum that describes API endpoints, where each endpoint is represented by a different Fooable class.

I suppose the problem arises because I dynamically obtain a type, so there can be no strong typing at compile time.

Is there a way to work around this?

like image 499
knl Avatar asked Mar 31 '16 17:03

knl


1 Answers

The problem is that this:

let fooableType: Fooable.Type = // obtain from somewhere else

... is casting into oblivion precisely the information you want to store in that variable, i.e. what is the concrete type that is conforming to Fooable. Consider that the following code compiles:

protocol Fooable {}

func fooingAround<FooableType: Fooable>(withType: FooableType.Type) {}

struct Foo: Fooable {}
fooingAround(Foo) // works fine

let foo = Foo()
let fooableType /* do not cast here */ = foo.dynamicType

fooingAround(fooableType) // also works fine

... which means that you have to find a way to directly pipe the type information into your function call without casting.

Depending on the sort of fooingAround you have in mind, you may for example be able to extend Fooable along the following lines:

extension Fooable {

    func fooingAround() {
        /* do some fooing with */ self.dynamicType // which is the Foo.Type when called on the `foo` value
    }
}

foo.fooingAround()
like image 127
Milos Avatar answered Nov 15 '22 05:11

Milos