Instance is necessarily treated as value type in extensions of non-class-bound protocols

89 views Asked by At

Here's the code:

protocol A {
  var a: Int { get set }
}

extension A {
  var convenientAccessor: Int {
    get { return a }
    set { a = newValue }
  }
}

class B: A {
  var a: Int = 0
}

func acceptsB (instance: B) {
  instance.a = 1                     // This compiles
  instance.convenientAccessor = 2    // This does not
}

I sort of understand the problem here, but I really would love both an answer from someone who understands it more deeply, and more importantly a workaround for my problem which is that I want to pass around known class types and be able to use convenient accessors without being inhibited by the non-possibility that I'm using a value type. In my case, the protocols which define these convenient accessors should not be class-bound (they are perfectly valid and useful for value types), so while that is technically a workaround, it is not satisfactory to me.

1

There are 1 answers

0
Cristik On

Let's start with a summary: convenientAccessor is a writable property, thus any assignment on it will result in a mutation. And this mutation happens inside your function.

The thing is that when the convenientAccessor property is used the compiler treats instance as protocol A, and because arguments to a function are let's, it doesn't allow mutations on them, as at this point the protocol can be implemented by a value type also.

Two solutions that come into my mind are:

  1. restrict protocol A to only classes:

    protocol A: class 
    

    This informs the compiler that only classes can conform to the protocol, which allows the mutation on any kind of variables (let or var)

  2. make the function parameter inout:

    func acceptsB (instance: inout B)
    

    This creates a "write hole" as now instance is writable, so any changes to it are propagated back upstream, even if B is a value type.

Personally, I'd go with #1 if you plan in using only classes, as you mentioned in the question.