Search code examples
swiftgenericsprotocols

Can you conditionally extend RawRepresentable to conform to another protocol?


Is there a way to add conformance to a protocol for types that already conform to RawRepresentable?

Consider a basic example of a class that can store primitive values in a sqlite database:

protocol DatabaseStoreable {}

extension Int: DatabaseStoreable {}
extension Double: DatabaseStoreable {}
extension String: DatabaseStoreable {}
extension Data: DatabaseStoreable {}

func storeValue<T: DatabaseStoreable>(_ value: T) {
  ...
}

I'd like to also include any type that conforms to RawRepresentable where RawValue: DatabaseStorable:

extension RawRepresentable: DatabaseStoreable where Self.RawValue: DatabaseStoreable {}

However, this generates the following error:

Extension of protocol 'RawRepresentable' cannot have an inheritance clause

Is there a way to work around this because at the moment I have to declare a second function with the following signature:

func storeValue<T: RawRepresentable>(_ value: T) where T.RawValue: DatabaseStoreable {
  // Calls through to the function above.
}

Solution

  • As your error message is already telling you there is no way to add inheritance to protocols. You only can add inheritance to objects.

    Therefore this won't work:

    extension RawRepresentable: DatabaseStoreable {}
    

    However, you could add an extension as this:

    protocol DatabaseStoreable {}
    
    extension Int: DatabaseStoreable {}
    extension Double: DatabaseStoreable {}
    extension String: DatabaseStoreable {}
    extension Data: DatabaseStoreable {}
    
    func storeValue<T: DatabaseStoreable>(_ value: T) {
         print("T store(\(value))")
    }
    
    extension RawRepresentable {
        func storeValue<T: DatabaseStoreable>(_ value: T) {
            print("RawRepresentable store(\(value))")
        }
    }
    
    enum Test: String {
        case A
        case B
    }
    
    class DataBaseStore: DatabaseStoreable {}
    
    let myTest = Test.A
    let databaseStore = DataBaseStore()
    myTest.storeValue(databaseStore) // prints RawRepresentable store(__lldb_expr_15.DataBaseStore)