qwerty_so
qwerty_so

Reputation: 36295

Cannot assign to immutable expression of type ... but with protocols

I know there are lots of questions starting like that. However, here's my code snippet:

protocol AProt { var a:Int { get set } }
protocol BProt { var b:Int { get set } }
protocol CProt { var c:Int { get set } }
class A:AProt, CProt { var a = 1;  var c = 3 }
class B:BProt, CProt { var b = 2; var c = 30 }

var a = A()
var b = B()
var c = a as CProt // works
c.c = 123
a = c as! A
print (a.c)
(a as CProt).c = 999 // throws error
print (a.c)

Looking at this answer it tells that the (...as...) makes the expression immutable. But ...

while the (a as CProt).c = 999 fails with above error message, the work around with the var c = a as CProt works. I'd regard this as simple compiler bug, but I wanted to know whether there's something that could be done here (like adding a secret key word).

Upvotes: 1

Views: 682

Answers (1)

Rob Napier
Rob Napier

Reputation: 299275

This isn't a compiler bug. CProt can be a value type. Consider this code:

protocol CProt { var c:Int { get set } }
struct A: CProt { var a = 1;  var c = 3 } // Note this is a struct
var a = A()  // It's mutable
let c = a as CProt  // But this one isn't
c.c = 999  // So no surprise this fails

Would you expect this to work? It shouldn't, since c is an immutable struct. This is the same thing you're writing in (a as CProt).c = 999.

The problem is you expect CProt to be a reference type. If you need that, then say so:

protocol CProt:class { var c:Int { get set } } // Note the addition of :class
class A: CProt { var a = 1;  var c = 3 }
let a = A()
(a as CProt).c = 999 // Success

Upvotes: 5

Related Questions