Skip to content

Meta Programming

Swift supports limited metaprogramming through reflection, dynamic member lookup, and callable types. Unlike languages with macros or runtime code generation, Swift’s metaprogramming is constrained for safety and performance.

Reflection

Use Mirror to inspect types at runtime.

Example: Basic Reflection:

swift
struct User {
    let id: String
    let name: String
    let age: Int
}

let user = User(id: "u1", name: "Alice", age: 30)
let mirror = Mirror(reflecting: user)
for child in mirror.children {
    print("\(child.label!): \(child.value)")
}
// Output:
// id: u1
// name: Alice
// age: 30

Example: Nested Reflection:

swift
struct Address {
    let city: String
}

struct Person {
    let name: String
    let address: Address
}

let person = Person(name: "Bob", address: Address(city: "New York"))
func printProperties(_ value: Any) {
    let mirror = Mirror(reflecting: value)
    for child in mirror.children {
        if let label = child.label {
            print("\(label): ", terminator: "")
            if Mirror(reflecting: child.value).children.isEmpty {
                print(child.value)
            } else {
                print("")
                printProperties(child.value)
            }
        }
    }
}

printProperties(person)
// Output:
// name: Bob
// address:
//   city: New York

Dynamic Member Lookup

Enable dynamic property access with @dynamicMemberLookup.

Example:

swift
@dynamicMemberLookup
struct DynamicDict {
    private var data: [String: Any]
    
    init(data: [String: Any]) {
        self.data = data
    }
    
    subscript(dynamicMember key: String) -> Any? {
        return data[key]
    }
}

let dict = DynamicDict(data: ["name": "Charlie", "age": 25])
print(dict.name) // "Charlie"
print(dict.age) // 25

Example: Type-Safe Lookup:

swift
@dynamicMemberLookup
struct JSON {
    private var data: [String: Any]
    
    subscript<T>(dynamicMember key: String) -> T? {
        return data[key] as? T
    }
}

let json = JSON(data: ["score": 95, "active": true])
print(json.score as Int?) // 95
print(json.active as Bool?) // true

Dynamic Callable

Allow dynamic function calls with @dynamicCallable.

Example:

swift
@dynamicCallable
struct Logger {
    func dynamicallyCall(withArguments args: [String]) {
        print(args.joined(separator: " "))
    }
    
    func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, String>) {
        print(args.map { "\($0): \($1)" }.joined(separator: ", "))
    }
}

let log = Logger()
log("Error", "occurred") // "Error occurred"
log(key: "value", another: "test") // "key: value, another: test"

KeyPath

Released under the MIT License.