Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Mutability of a class after conforming to protocol is in question

I was trying to implement a Networking Module for my personal project and I was following TDD. When I am writing the test cases I came across a compile error and I was not able to map the error with Swift concepts. I could have easily ignored it and done the implementation in a different way. But I was not feeling right to do it as I want to know the exact reason to the error.

This is the code snippet.

import UIKit

protocol HTTPClient {
    var url: String? {get set}
    func load()
}

class HTTPClientSpy: HTTPClient {
    var url: String?
    
    func load() {
        
    }
}

class Feed {
    let client: HTTPClient

    init(client: HTTPClient) {
        self.client = client
    }

    func loadFeed() {
        client.url = "" //Compile Error -> Cannot assign to property: 'client' is a 'let' constant
        client.load()
    }
}

When I do the following change the error goes away

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class Feed {
    let client: HTTPClientSpy

    init(client: HTTPClientSpy) {
        self.client = client
    }

    func loadFeed() {
        client.url = "" //No compile errors
        client.load()
    }
}

Swift classes are mutable. which means we should be able to change the properties of the instance even if we create a constant reference to the instance. It seems there is something to do with the protocol conformance in this case which I cannot understand.

Can someone please explain the theory behind this?

>Solution :

Swift classes are mutable. which means we should be able to change the properties of the instance even if we create a constant reference to the instance.

Indeed you are right. But structs can conform to your HTTPClient protocol too:

struct SomeStruct: HTTPClient {
    var url: String?
    func load() {}
}

If Feed were passed an instance of SomeStruct, then client.url = "" would not work. Normally you cannot change the vars of a struct-typed variable, if you declared the variable with let.

let client = SomeStruct()
client.url = "" // error

The compiler doesn’t know whether client in Feed is storing a struct or a class, so it tries to be safe and doesn’t let you change url.

You can make sure that only classes can conform to the protocol by adding : AnyObject:

protocol HTTPClient: AnyObject {
    // ...
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading