I've come up with a, possibly simpler, solution to setting values by key paths on unknown types in a project of my own.

The requirements for the unknown type were :

public weak var subject: (AnyObject & KeyPathDeclaration)!

… where KeyPathDeclaration is :

public protocol KeyPathDeclaration
{
  static var keyPaths: [String : AnyKeyPath] { get }
}

extension KeyPathDeclaration
{
  public static func keyPathForProperty(name: String) -> AnyKeyPath?
  {
    return keyPaths[name]
  }
}

This is then implemented in a type like this :

struct Person
{
  var name: String
  
  var age: Int
}

extension Person : KeyPathDeclaration
{
  public static var keyPaths: [String : AnyKeyPath]
  {
    return ["name" : \Person.name, "age" : \Person.age]
  }
}

The problem arises when you need to use one of the key paths to set a value where the exact type of the target object is only known as :

  public weak var subject: (AnyObject & KeyPathDeclaration)!

… where trying to use subject[keyPath:_] to set a value provokes an error

"Cannot assign to immutable expression of type 'Any?'"

So, I played around for a bit and started thinking about some of the ideas in this thread. Here's what I came up with.

First, I create a new protocol :

public protocol KeyPathValueSetter
{
  func set<valueT>(_ value: valueT?, for keyPath: AnyKeyPath)
}

extension KeyPathValueSetter
{
  public func set<valueT>(_ value: valueT, for keyPath: AnyKeyPath)
  {
    if let keyPath = keyPath as? ReferenceWritableKeyPath<Self, valueT>
    {
      self[keyPath: keyPath] = value
    }
  }
}

Then I add in this protocol to the subject's requirements :

  public weak var subject: (AnyObject & KeyPathValueSetter & KeyPathDeclaration)!

Now I can set the value on the subject like this :

      let keyPath = type(of: subject).keyPathForProperty(name: propertyName)

      subject.set(value, for: keyPath)

Not quite a subscript but a lot more concise than some efforts I made to solve this :wink::sunglasses:

Why is the first parameter optional?

To allow the possibility of optional properties? Or it could just be a typo :roll_eyes::wink: