Swift Dynamic Member Lookup Types

Apr 20, 2023#swift

In Swift, dynamic member lookup types using attribute @dynamicMemberLookup enable you to access properties of a type that are not declared at compile time, but resolved at runtime. This can be useful for interoperability with dynamic languages such as Python, Ruby, or JavaScript, or for proxy-based code.

To use @dynamicMemberLookup, you need to implement a subscript method subscript(dynamicMember:) that takes a string or a key path as an argument and returns any value you like.

  1. Using string member name to create a wrapper type around data that can’t be type checked at compile time, such as when bridging data from other languages into Swift.
@dynamicMemberLookup
struct Person {
    subscript(dynamicMember member: String) -> String {
        let properties = ["name": "Taylor Swift", "city": "Nashville"]
        return properties[member, default: ""]
    }
}

let taylor = Person()
print(taylor.name) // Taylor Swift
print(taylor.city) // Nashville
print(taylor.favoriteIceCream) // ""
  1. Using keypaths to implement a wrapper type that supports compile-time type checking.
@dynamicMemberLookup
struct Person {
    var name: String
    var address: Address
    
    subscript<T>(dynamicMember keyPath: KeyPath<Address, T>) -> T {
        return address[keyPath: keyPath]
    }
}

struct Address {
    var street: String
    var city: String
}

let address = Address(street: "123 Main St", city: "Anytown")
let person = Person(name: "John Doe", address: address)

print(person.name) // prints "John Doe"
print(person.street) // prints "123 Main St"
print(person.city) // prints "Anytown"

This feature can reduce boilerplate code and improve readability when accessing properties that are not known at compile time. However, it can introduce runtime errors and unexpected behavior if the property names are misspelled or not available. It can also reduce type safety and code completion support, as the compiler cannot check or infer the types of the properties.