0

In the following Swift code, for some types T:HasDefaultValues, the assignment in init(variableValue: T) does not happen and the member variable takes the value of T.defaultValue:

protocol HasDefaultValues : Equatable {
  static var defaultValue: Self {get}
  static var alternativeValue: Self {get}
}

class MyClass<T:HasDefaultValues> : NSObject, NSCoding {
  var variable: T = T.defaultValue

  init(variableValue: T) {
    self.variable = variableValue // Executed, but assignment doesn't happen!
    super.init()
  }

// ... More code follows
}

I have single-stepped the code using the debugger, and confirmed that the value of variableValue is as expected, that execution passes over the self.variable = variableValue assignment, but that the value of self.variable does not change. The code works as expected for numerous other types T:HasDefaultValues. Might this be a compiler bug?

The code for the type T:HasDefaultValues for which assignment isn't happening is quite complex, and I've not tried to reduce things to a minimal reproducible example. I'm asking here if there are good reasons for a simple assignment to fail other than a compiler bug. If there are, this would be useful in reducing things to a minimal reproducible example.

Thanks in advance.

Chris
  • 941
  • 9
  • 18
  • 2
    Please show us a verifiable, working example so we can verify this behaviour for you. I.e., you should be able to include (a downsized example) of your conformance to `NSCoding` in `MyClass`, as well as some simple example usage of `MyClass` for some type extended by and conforming to `HasDefaultValues`. – dfrib Jan 21 '16 at 13:44
  • 1
    You can declare your variable as `let`, if you don't plan to change it during the lifecycle of the code, this will give you more stability to the source code. – Cristik Jan 21 '16 at 13:56
  • @Cristik As `variable` is set to a default initial value, it wont be mutable in the initializer if declared as a immutable variable (`let`). – dfrib Jan 21 '16 at 13:58
  • 1
    You can not give it an initial value, and set in in the initializer – Cristik Jan 21 '16 at 14:00
  • @Cristik You can, if it's a mutable (`var`). This is possibly usable when offering several initializers (`init()` and `init(newStartValue: T)`) to caller. – dfrib Jan 21 '16 at 14:02
  • @dfri not sure I follow you. You can have an uninitialized `let` and multiple initializers that set the value. – Cristik Jan 21 '16 at 14:06
  • @Cristik We're probably both misunderstanding each other :) My initial comment to you was regarding _"you can declare your variable as `let`"_: _if_ OP were to change `variable` from `var` to `let`, then he'd break his code, as he wont be able to mutate it in his initializer above (since he _already sets a default value to it_ (see `... variable: T = T.defaultValue`) when declaring it in the class). – dfrib Jan 21 '16 at 14:09
  • @Cristik is correct: in my scenario, the variable needs to be a var so that it can have a default initial value and be mutated later. – Chris Jan 21 '16 at 15:16
  • @Chris: if you are mutating the `var` only inside an initializer you should really use a constant (`let`). – Luca Angeletti Jan 21 '16 at 16:25

1 Answers1

2

I think some code is changing again the variable property.

Please add an observer to check this "theory".

var variable: T = T.defaultValue {
    didSet(oldValue) {
        debugPrint("variable changed from \(oldValue) to \(variable)")
    }
}
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 1
    Thanks for this. The `variable` property is not being set again by something else, but the suggestion to use `didSet` has been really helpful. I've not figured out exactly what is going on, but I have a bit more information now. – Chris Jan 21 '16 at 15:37