0
class Actor {
    let agent: String? = "nobody"

    init(agent: String){
        self.agent = agent // error: immutable value 'self.agent' may only be initialized once
    }
}

let John = Actor(agent: "xyz")

I'm confused about the sequence that is happening here (I'm fully aware of the differences between var and let). But why do I get that error?

  • If I'm using the init method, then doesn't that mean I'm not using the default parameter?
  • Why can't I change the default constant with another one?
mfaani
  • 33,269
  • 19
  • 164
  • 293

1 Answers1

3

You cannot assign a let variable more than once - however, you can define it and leave it uninitialized. Then in your init method, you can have "nobody" as the default value for the agent argument.

class Actor {
    let agent: String

    init(agent: String = "nobody"){
        self.agent = agent
    }
}

print(Actor().agent) // "nobody"
print(Actor(agent: "xyz").agent) // "xyz"

As Alexander suggested in the comments below, if you have too many arguments in your init method, default values can get a little messy. Consider creating a separate init method that sets the default values.

class Actor {
    let agent: String
    ...

    init() {
        self.agent = "nobody"
        ...
    }

    init(agent: String, ...){
        self.agent = agent
        ...
    }
}
Callam
  • 11,409
  • 2
  • 34
  • 32
  • 1
    Yep, this is definitely the way to go if you only have a few values to set defaults for. If you have more than 2-3, it's probably better to define a separate initializer, which takes no params, which sets all the default values. – Alexander Feb 09 '17 at 19:47
  • @Alexander The paradox here I don't understand is, you either read the properties or don't. If you read, then yes my answer, my code should fail, as should `let agent : String?` **or is that it reads this line, yet nothing happens to it at this moment?! because it's stupid for it default to nil and be stuck there as mentioned [here](http://stackoverflow.com/questions/38942325/constant-unassigned-optional-will-not-be-nil-by-default). Basically it's an exception** if you don't read it then, I shouldn't be getting the error. – mfaani Feb 09 '17 at 19:58
  • @Honey I don't understand what youre saying – Alexander Feb 09 '17 at 20:00
  • @Alexander in my code from my question, does it first read the `let agent: String? = "nobody"` **then** come to the `init` – mfaani Feb 09 '17 at 20:01
  • 1
    @Honey yep, that's why the init counts as reassignment, which violates the "let" – Alexander Feb 09 '17 at 20:02
  • 2
    Why make `agent` optional? If it is properly set in all initializers, don't make it optional. – rmaddy Feb 09 '17 at 20:04
  • Once you assign a let, you're initializing it, and this can only be done once. The difference between `let agent: String? = "nobody"` and `let agent: String?` is that latter hasn't been initialized with a value. – Callam Feb 09 '17 at 20:04
  • @Alexander so how come the init in this **answer** doesn't violate the `let`? Is it because of what I [this](http://stackoverflow.com/questions/38942325/constant-unassigned-optional-will-not-be-nil-by-default)? – mfaani Feb 09 '17 at 20:04
  • @Honey because the assignment is always done exactly once. Either in one initializer, OR the other – Alexander Feb 09 '17 at 20:05
  • Also, @rmaddy has a point about agent not being optional. It doesn't make a difference in terms of it's mutability. – Callam Feb 09 '17 at 20:06
  • @Alexander my question is: isn't `let agent: String?` also an assignment? is it not an assignment because of what I linked? – mfaani Feb 09 '17 at 20:12
  • @Honey No, it's only a declaration. Assignment is the `=` operator – Alexander Feb 09 '17 at 20:13
  • @Alexander so how come if you do in playground: `var m : String? ; print(m)` it will print it with `nil` as if it's assigned – mfaani Feb 09 '17 at 20:14
  • @Honey Optional vars default to `nil` until you assign something else. I dont see how that's relevant, though. – Alexander Feb 09 '17 at 20:15
  • @Alexander you said you can only assign a `let` once. if it defaults to `nil` then it can't be assigned again. right? yet it means that `let agent String?` **doesn't** default to `nil` otherwise you won't be able to set it again – mfaani Feb 09 '17 at 20:19
  • @Honey no, a `let` doesn't default to `nil`. `var` does. – Alexander Feb 09 '17 at 20:19