Dynamic member lookup on specific typed properties

I have a number of properties known at compile time, including type information. However, I need to handle the setting and getting at runtime. The simplest syntax I've been able to implement uses a set pattern and a few functions (below), but it's nothing close to what is possible with @dynamicMemberLookup:

class Person {
    
    var name : String? {
        get { return member() }
        set { setMember(newValue) }
    }

    func setMember(_ newValue: String?, member: @autoclosure () -> String = #function) {
        print("Set \(newValue ?? "nil")")
    }

    func member(member: @autoclosure () -> String = #function) -> String? {
        return "Get"
    }
}

let taylor = Person()
taylor.name = "Taylor"

The ideal (for me) would be to able to write it using something like this (below) but that's not allowed. Can anyone suggest any improvements I could make to bring the first code block closer to the second?

class Person {
	dynamic var name : String?
	    
	subscript(dynamicMember member: String) -> String? {
		get {
			return "Get"
		}
		set {
			print("Set \(newValue ?? "nil")")
		}
	}
}

let taylor = Person()
taylor.name = "Taylor"

Since you have the member statically already, there’s nothing dynamic about the member lookup. Why not just set name directly?

I need to define the property type within the class definition, but handle the setting and getting at runtime. Currently, I have 2 choices:

  1. Define the property in the class and provide accessors (shown in my initial post). This keeps me safe but hides the property definition with a pile of visual boilerplate.
  2. Use @dynamicMemberLookup (shown below), which removes the boilerplate and the definition and is so much worse.
@dynamicMemberLookup
class Person {
    // var name : String?
    subscript(dynamicMember member: String) -> String? { ... }
    subscript(dynamicMember member: String) -> Int? { ... }
}

let taylor = Person()
taylor.name = "Taylor"
taylor.name = 1 // VERY VERY BAD
taylor.nameWithBellsOn = "Taylor" // VERY VERY BAD

If you meant to define a custom setter and getter for a property, wouldn't a computed property solve your problem?

class Person {
  var name: String {
    get {
      // get whatever you need
    }
    set {
      // set whatever you need
    }
  }
}

Like you described, the property is statically defined. I don't think it's a proper use case of dynamic member lookup - there's nothing dynamic about looking up this member.

Setting and getting always happen at runtime no matter the property is statically defined or not. I think what you were looking for is custom getters and setters like as shown above.

Custom getters and setters are exactly what I'm using right now (see the first code block in my original question), but as you can see, there's a bunch of boilerplate code to wire everything up.

To summarise, I'd like to use the dynamic member lookup methods for multiple defined (and marked) properties. It seems like the functionality is in there just not surfaced. Regardless, I'd like to make improvements in what I've got based on what's currently possible.

I think you're asking for something like the @NSManaged attribute, where the implementation of a computed property can be provided dynamically at runtime. I don't think this is possible in Swift, without also using the Objective-C runtime.

Edit: The more general attribute is @objc dynamic (see SE-0160).

1 Like

Thanks for everyone's help. I created a pitch Allow dynamic keyword on non-objc properties.

Terms of Service

Privacy Policy

Cookie Policy