A puzzle showed up on Twitter the other day. It exercises overload resolution and type(of:) together. This is just a note for myself; I’ll write up MetaType separately.
// Swift Quiz
class View {}
class A: View {}
class B: View {}
func add(_ v: View) { print(type(of: v)) }
func add(_ v: A) { print(type(of: v)) }
func add(_ v: B) { print(type(of: v)) }
func build() -> View { return B() }
add(build())
// What is the output?
- "View"
- "A"
- "B"
Judging from the spread of answers, this one is genuinely confusing 🤔.
The three add overloads are a small misdirection. Overload resolution in Swift uses the static type of the argument — so what matters is the declared return type of build(), which is View. That means the add(_ v: View) overload is the one that gets called.
Inside that overload, the output then depends on type(of:). Apple’s signature is:
func type<T, Metatype>(of value: T) -> Metatype
You can use the type(of:) function to find the dynamic type of a value, particularly when the dynamic type is different from the static type. The static type of a value is the known, compile-time type of the value. The dynamic type of a value is the value’s actual type at run-time, which can be a subtype of its concrete type.
So type(of:) returns the dynamic type of the value — its real runtime type. In this case the value handed to add was actually constructed from B, so its dynamic type is B.

Comments
Questions or thoughts? Join the conversation with your GitHub account. Comments are public.
You can also read and join discussions on GitHub ↗