What is `Metatype` that `type(of:)` returns?

Hey everyone,

we're doing some extensive usage of type(of:) to verify the contents of some collections of values that adhere to a bunch of protocols in our tests. I'm re-reading the documentation of type(of:) Apple Developer Documentation and since the return type Metatype in the docs isn't clickable am wondering where can I learn more about that type.

It seems that you can compare two results of type(of:) with ==(::) here Apple Developer Documentation so Metatype must be a Type too but I'd love to see if there are any docs about it.

-- Marin

1 Like

The Metatype that type(of:) returns is the "type of a type", e.g., a type which represents information about the type of something else. For instance, the type of 42 may be Int, and the type which represents the Int type itself (i.e., the metatype of Int) can be referred to as Int.self. Metatypes are regular values in and of themselves, though are largely handled pretty specially by the compiler, so you won't find much about them by, e.g., Cmd-clicking in Xcode because their implementation is largely in the Swift compiler itself rather than in Swift source code. (Metatypes also have metatypes themselves, e.g. Int.Type.self represents the metatype of the metatype of Int, and Int.Type.Type.self represents... and so on ad infinitum.)

As far as the source of type(of:) itself, Metatype is regular generic argument that is bound by the type checker in the compiler to be the actual type of the argument that you pass in; i.e., the compiler figures out the actual runtime type of the value you pass in, and gives it back to you (e.g. type(of: 5) → Int.self). (The name Metatype isn't actually special here — it would work identically if it were called Foo or R or anything else.)

The Swift Reference Manual page on types has slightly more information about metatypes that might be helpful, though it is a bit brief. The compiler docs has a Lexicon.md reference which also briefly mentions metatypes, and the rest of the compiler docs have a few more hits if you want to see a bit more related information. Otherwise, the best reference will the the actual compiler source, but that's more dense to get through.

More Info on type(of:) specifically

The thing that is special about Metatype is how the compiler figures out what the value of the argument should be, because typically, the concrete values of generic arguments are figured out based on how those arguments are used in the function, and how the function is called. (And if you notice, Metatype isn't actually used anywhere as input to the function itself!) But the resulting value could be any old type, and there's nothing special about it.

It feels weird to “plug” an SO answer here, but some additional material I put together a while back that describes how this function works in a bit more detail: swift - Why does type(of:) return Metatype, rather than T.Type? - Stack Overflow

6 Likes

I'll note that meta-types are objects on their own, which can participate in polymorphism.

The metatype describes the static (or class) functions of a type, the same way a regular type describes the instance functions of its instances.

protocol MyProtocol {
    static func staticMethod()
}

struct Imp1: MyProtocol {
    static func staticMethod() { print("Imp1") }
}

struct Imp2: MyProtocol {
    static func staticMethod() { print("Imp1") }
}

let someImplementation: MyProtocol.Type = Imp1.self

// A polymorphic call to a static method
someImplementation.staticMethod()

I'll take a turn and plug a semi-related SO answer of my own: ios - Static function encapsulation in Swift by passing Protocols.Type better than OO encapsulation and just as testable? - Stack Overflow

As an interesting point of comparison, you can see that the class_getClassMethod() function of the Objective C runtime is really just a wrapper that calls class_getInstanceMethod on the metaclass:

1 Like

One small edit here — the type of Int is Int.Type. Int.self is the (only) instance of Int.Type, just like 42 is an instance of Int.

7 Likes

Indeed — sloppy language on my part, sorry! (This is what I meant to allude to with "referring", but your phrasing is much better, so I'll leave it.)

1 Like