Value semantics in classes

(Srđan Rašić) #1

I'm curious why do mutating properties or methods defined in a protocol extension have value semantics when the protocol is implemented by a class.

Let's say we have a protocol and a mutating member implemented in an extension:

protocol P {}

extension P {

    var p: Int {
        get {
            return 5
        }
        set {
            _ = newValue
        }
    }
}

If we make a class that implements the protocol and try to modify p of a class instance, we get the compiler error:

class C: P {}

let c = C()

c.p = 10 // error: cannot assign to property: 'c' is a 'let' constant

Is this just a limitation in the current Swift compiler or the behaviour is expected and why?

(Benjamin Mayo) #2

I'm not sure if this limitation could be lifted in cases where the compiler can locally prove the instance is a class, but at least right now you need to indicate your protocol is class based.

Declare protocol P : AnyObject {} and you can assign with reference semantics.

(Srđan Rašić) #3

I'm aware that declaring a protocol like P : AnyObject or P : class will yield the expected behaviour, but I would also expect the reference semantics even without doing that when the instance is known to be of a reference type.

(Joe Groff) #4

From the extension's point of view, it doesn't know whether it's getting applied to a class or not. If you define a mutating operation in the extension, it could wholesale replace the reference:

extension P {
  mutating func swap(with x: inout Self) {
    let tmp = x
    self = tmp
    x = tmp
  }
}

and since we can't rule out that possibility from the call site, the reference you invoke the method on must be mutable.

7 Likes
(Srđan Rašić) #5

Ah, that makes perfect sense. Thanks for the explanation!