Search code examples
swiftprotocols

Multiple protocol and class inheritance confusion, Swift


So I know a class can only inherit a single class but can inherit multiple protocols. I am looking at some code here and confused as to why swift is throwing me an error.

protocol PaymentViewModelConfigurable: ViewModelWithResult {
    
}

class ViewModelWithResult {
    func printWithResultClass() {
        print("In View Model with result class")
    }
}

class PaymentViewModel: PaymentViewModelConfigurable {
    
    
}


class MainOne {
    let viewModel: PaymentViewModelConfigurable = PaymentViewModel()
}

So I would assume this is ok because my PaymentViewModel class inherits a protocol and that protocol inherits from a class.

But if I change the logic to this on my ViewModel to inherit the protocol & the class, its fine 😕

protocol PaymentViewModelConfigurable: ViewModelWithResult {
    func payments()
}

class ViewModelWithResult {
    func printWithResultClass() {
        print("In View Model with result class")
    }
}

class PaymentViewModel: ViewModelWithResult, PaymentViewModelConfigurable {
    func payments() {
        print("Payments")
    }
}


class MainOne {
    let viewModel: PaymentViewModelConfigurable = PaymentViewModel()
    
    init() {
        viewModel.payments()
    }
}

These are the errors that come up:

'PaymentViewModelConfigurable' requires that 'PaymentViewModel' inherit from 'ViewModelWithResult'

Type 'PaymentViewModel' does not conform to protocol 'PaymentViewModelConfigurable'


Solution

  • So I know a class can only inherit a single class but can inherit multiple protocols.

    Not quite. A class can conform to multiple protocols. It might seem like a pedantic correction of wording, but it's actually core to the issue here. The conformance and inheritance features are related and interconnected, but distinct. Similarly:

    and that protocol inherits from a class.

    It doesn't.

    Everything after the : on a declaration of a protocol is not a list of superclasses and protocol conformances, like with classes. It's a list of requirements of that protocol. So this declaration:

    protocol PaymentViewModelConfigurable: ViewModelWithResult {
        func payments()
    }
    

    Is saying: "PaymentViewModelConfigurable is a protocol that can be conformed to anything that's a subtype of ViewModelWithResult and has a func payments() method. It's as if you had written:

    protocol PaymentViewModelConfigurable where Self: ViewModelWithResult {
        func payments()
    }
    

    The error messages spell this out quite explicitly:

    Untitled 4.swift:11:7: error: 'PaymentViewModelConfigurable' requires that 'PaymentViewModel' inherit from 'ViewModelWithResult'
    class PaymentViewModel: PaymentViewModelConfigurable {
          ^
    Untitled 4.swift:11:7: note: requirement specified as 'Self' : 'ViewModelWithResult' [with Self = PaymentViewModel]
    class PaymentViewModel: PaymentViewModelConfigurable {
          ^