Swift class introspection generics
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Swift, reflection and generics intersect in a limited but useful way. You can inspect runtime values with tools such as type(of:) and Mirror, and you can write generic code that preserves type information at compile time. What you cannot do is expect full dynamic runtime introspection of generic types in the same style as a highly dynamic language.
Start with the Two Different Mechanisms
Swift gives you two different capabilities that are often mixed together:
- generic type information known at compile time
- runtime reflection of values and types
Generics are primarily a compile-time feature. Reflection is a runtime feature. They overlap, but they are not the same system.
Inspecting the Dynamic Type of a Value
The simplest runtime introspection tool is type(of:).
This prints the dynamic runtime type of the instance, which is often the first thing people want from introspection.
You can also compare metatypes directly:
That works well when you need type-based branching.
Generic Functions Preserve Type Information
Inside a generic function, Swift keeps the concrete type parameter available to the compiler and to some runtime metadata operations.
For value types, T.self and type(of: value) are often the same. For protocol and class hierarchies, they can differ in meaningful ways depending on how the function is called.
Using Mirror for Structural Reflection
Mirror is Swift's main public reflection API for inspecting stored properties and child values.
Mirror is useful for debugging, generic display code, and lightweight inspection. It is not intended to replace a full metadata or serialization framework.
Introspecting Generic Types
If you have a generic class, you can still inspect its concrete instantiation through normal Swift type operations.
This lets you distinguish Box<Int> from Box<String> at the type level.
What Swift does not provide as a clean public API is a rich structured reflection interface for "give me the generic parameter list of an arbitrary runtime object and let me manipulate it dynamically". You can often observe the type name, but generic programming in Swift is not designed around deep runtime metaobject manipulation.
Protocol Constraints Are Often Better Than Reflection
A lot of developers reach for introspection when a protocol constraint or overload would be cleaner.
This is usually preferable to reflecting over a value and hoping it has a field called name.
In Swift, strong type constraints are normally the first tool, and reflection is the fallback for diagnostics or generic infrastructure.
Objective-C Runtime Is a Different Layer
If a type is NSObject-based and exposed to the Objective-C runtime, additional introspection tools such as NSStringFromClass and Objective-C runtime functions become available.
That can help in UIKit and Foundation-heavy code, but it is not the general answer for all Swift generic introspection problems.
Common Pitfalls
A common mistake is expecting Mirror to be a full runtime metadata system for arbitrary generic manipulation. It is much lighter-weight than that.
Another mistake is using reflection where protocol constraints or normal generic design would be clearer and safer.
People also often confuse T.self with type(of: value). One refers to the generic type parameter in context, and the other refers to the runtime dynamic type of the value.
Finally, do not assume Objective-C runtime tools apply to pure Swift value types or non-Objective-C class hierarchies in the same way.
Summary
- Swift generics are mainly compile-time, while reflection is mainly runtime
- Use
type(of:)to inspect the dynamic type of a value at runtime - Use
T.selfinside generic code to refer to the concrete generic type parameter - Use
Mirrorfor lightweight structural reflection of stored properties - Reflection is limited compared with dynamic languages, so prefer protocols and generic constraints when possible
- Objective-C runtime introspection is useful for bridged classes, but it is not the general solution for all Swift generic type questions

