Store type in variable

I already asked this question on stackoverflow, but unfortunately I didn't get any answer yet. So I hope that maybe someone here can help me?

To explain my problem, I simplified my code (I removed parameters and properties that are not necesseary to show the problem):

I have a generic function like this:

func genFunc<T: Codable>(test: T.Type) {
    // do some database stuff and use the type to decode the data
}

Let's use this dummy struct:

struct Test: Codable {
    let name: String
}

Now I can call this function with the type of this struct:

genFunc(test: Test.self)

But in my specific case I don't know yet the type I want to pass. So I try to store it in a variable:

var type: Codable.Type
type = Test.self
genFunc(test: type)

If I do this, I get the error: Generic parameter 'T' could not be inferred

What can I do?

What you are looking for is called "opening existentials" and currently it is not implemented in Swift. There were some discussions around hypothetical syntax, which would allow to write in your case something like this:

var type: Codable.Type = ...
let <T> _ = type // Opens existential type and introduces T into scope as a generic type
genFunc(test: T.self)

But good news is that there is a workaround. In protocol extensions you can use Self as an opened type.
So in your case, you need something like this:

extension Codable {
    static func callGenFunc() {
        genFunc(test: Self.self)
    }
}

var type: Codable.Type = ...
type.callGenFunc()
4 Likes
extension Codable {  ... }

^^^^^

error: non-nominal type 'Codable' (aka 'Decodable & Encodable') cannot be extende

So seems you can only extend either Encodable or Decodable or both but separately?

There is no way to call:

func genFunc<T: Codable>(test: T.Type) { ... }

only:

func genFuncE<T: Encodable>(test: T.Type) { ... }
func genFuncD<T: Decodable>(test: T.Type) { ... }

?

Just spell it out:

extension Decodable where Self: Encodable {
  // ...
}
2 Likes

Thanks for that solution. It's a workaround. But I shouldn't have simplified my code too much, because this way is not working anymore, when the genFunc is in a struct:

protocol DBEntry: Codable {}
struct Test: DBEntry {
	let name: String
}

extension DBEntry {
	static func callGenFunc() {
		genFunc(test: Self.self)    // of course this is not working!
	}
}

struct SomeStruct {
	
	func genFunc<T: Codable>(test: T.Type) {
		// ....
	}
	
	func doStuff() {
		var type: DBEntry.Type
		type = Test.self
		type.callGenFunc()
	}
	
}

Is there any way for that? I cannot make genFunc static in this case, because I need to access some properties in the struct.

Just pass self as a parameter to callGenFunc

Stupid me.... of course :rofl: thank you very much!

Terms of Service

Privacy Policy

Cookie Policy