title: Swift: Constrain a generic variable to be a class or a protocol
body: <p>As <code>KeyPath</code> can't be casted to super types in Swift, I want to write a type-erased version, which represents any <code>KeyPath</code> whose value could be casted to a specific protocol or super type:</p>
  
  <pre><code>public struct PropertyGetter&lt;Root, ValueType&gt; {
    private let keyPath: PartialKeyPath&lt;Root&gt;
  
    public init&lt;T: ValueType&gt;(_ keyPath: KeyPath&lt;Root, T&gt;) {
      self.keyPath = keyPath
    }
  
    public func get(_ instance: Root) -&gt; ValueType {
      return instance[keyPath: self.keyPath] as! ValueType
    }
  }
  </code></pre>
  
  <p>The compiler rightfully complains that</p>
  
  <blockquote>
    <p>type 'T' constrained to non-protocol, non-class type 'ValueType.Type'</p>
  </blockquote>
  
  <p>as <code>ValueType</code> could potentially be a struct type.</p>
  
  <p>So how do we properly constrain this? That is enforcing that</p>
  
  <ol>
  <li><code>ValueType</code> is either a class type or a protocol, i.e subclassable / implementable</li>
  <li><code>T</code> is constrained to conform to <code>ValueType</code>, i.e <code>x as! ValueType</code> must be guranteed to work, where <code>x: T</code></li>
  </ol>
  
  <hr>
  
  <p>Notice that it is indeed possible to write such a type-erasing struct, when the Protocol type is fixed. E.g a class which only accepts <code>KeyPath</code>s pointing to <code>CustomStringConvertible</code> members:</p>
  
  <pre><code>public struct CustomStringConvertibleGetter&lt;Root&gt; {
    private let keyPath: PartialKeyPath&lt;Root&gt;
  
    public init&lt;T: CustomStringConvertible&gt;(_ keyPath: KeyPath&lt;Root, T&gt;) {
      self.keyPath = keyPath
    }
  
    public func get(_ instance: Root) -&gt; CustomStringConvertible {
      return instance[keyPath: self.keyPath] as! CustomStringConvertible
    }
  }
  
  let getter1 = CustomStringConvertibleGetter(\SomeClass.someString) // works
  let getter2 = CustomStringConvertibleGetter(\SomeClass.nonConformingMember) // will throw an error at compile time
  </code></pre>