Cannot assign to property in protocol - Swift compiler error

I'm banging my head against the wall with the following code in Swift. I've defined a simple protocol:

protocol Nameable {
    var name : String { get set }
}

and implemented that with:

class NameableImpl : Nameable {
    var name : String = ""
}

and then I have the following method in another file (don't ask me why):

func nameNameable( nameable: Nameable, name: String ) {
    nameable.name = name
}

The problem is that the compiler gives the following error for the property assignment in this method:

cannot assign to 'name' in 'nameable'

I can't see what I'm doing wrong... The following code compiles fine:

var nameable : Nameable = NameableImpl()
nameable.name = "John"

I'm sure it's something simple I've overlooked - what am I doing wrong?


@matt's anwer is correct.

Another solution is to declare Nameable as a class only protocol.

protocol Nameable: class {
//               ^^^^^^^ 
    var name : String { get set }
}

I think, this solution is more suitable for this case. Because nameNameable is useless unless nameable is a instance of class.


It's because, Nameable being a protocol, Swift doesn't know what kind (flavor) of object your function's incoming Nameable is. It might be a class instance, sure - but it might be a struct instance. And you can't assign to a property of a constant struct, as the following example demonstrates:

struct NameableStruct : Nameable {
    var name : String = ""
}
let ns = NameableStruct(name:"one")
ns.name = "two" // can't assign

Well, by default, an incoming function parameter is a constant - it is exactly as if you had said let in your function declaration before you said nameable.

The solution is to make this parameter not be a constant:

func nameNameable(var nameable: Nameable, name: String ) {
                  ^^^

NOTE Later versions of Swift have abolished the var function parameter notation, so you'd accomplish the same thing by assigning the constant to a variable:

protocol Nameable {
    var name : String { get set }
}
func nameNameable(nameable: Nameable, name: String) {
    var nameable = nameable // can't compile without this line
    nameable.name = name
}