Usage of “metatypes” as function parameters

Hello forums! Apologies if “metatype” is the wrong jargon to be using here… I don’t fully understand what I am about to describe :)

I’m playing with potential approaches to implementing a dependency injection library of some kind. I have written this method on a simple “Container” class:

func register<T>(_ value: T, for types: [T.Type]) {
    for type in types {
        let key = HashableType(typeValue: type)
        storage[key] = value
    }
}

I want to store instances of types in a dictionary, indexed by the type. This is a fragment of the “THC” pattern from Java, if you are familiar with that. I’d like to be able to call this method like this:

resources.register("foobar", for: [String.self, Any.self])
// => error: cannot invoke 'register' with an argument list of type '(String, for: [Any])'

The line above doesn’t compile. However, these two lines work:

resources.register("foobar", for: [String.self]) // works ok
resources.register("foobar", for: [Any.self])

I’m sure this has something to do with how the metatypes String.self and Any.self are or are not related at compile-time, but I’ve been unable to find any more information on this topic. Does anyone know if what I am attempting is possible?

Alternatively, if anyone has any pointers to background reading on the whole .self / .Type situation, I’d love to educate myself more about it. Cheers!

Peter

EDIT: sorry for disappearing, looks like my new account has been moderated and I can’t reply. @Nevin has it correct; I want to pass an array of supertypes of the value provided (an array of types that are “implemented” by the value provided)

The issue here is that when you define a function like so:

func register<T>(_ value: T, for types: [T.Type])

T is bound to a type based on its parameters. When calling it with [String.self] T is inferred to be String, and , and when called with [Any.self] T is Any. However, when calling it with [String.self, Any.self], there’s no way to find a single type for them. I’m not sure how to solve this issue, so I’ll defer to others on the list if they can come up with a solution.

Do I understand correctly that you are trying to pass in “an array of types which are supertypes of T”?

From what I understood, @ptomaselli is trying to represent “an array of any kind of Types”.

If I recall correctly, [Any.Type] should do the trick here. Keep in mind do not use SomeProtocol.self in a generic context because it will be magically transformed to SomeProtocol.Protocol and not as you‘d expect SomeProtocol.Type. Metatypes is an area I wish we could clean up, but it requires a source breaking change and we need some implementors with the know-how for that task.

Here is what we had in mind:

1 Like

Yes, exactly. :)