I discovered a confusing bug in the compiler when attempting to modify a member in the didSet observer. This bug requires calling a mutating function on oldValue and it needs to be defined more than once.
In my code, I created an Observable protocol which contains a mutating removeObserver() function. I then have a class which inherits from NSObject (which defines its own removeObserver as part of KVO) and implements my Observable protocol. An instance of this SomeClass is attached to an AnotherClass instance as a member variable.
When attempting to call oldValue.removeObserver() in the didSet of the SomeClass variable, the compiler will throw the following errors:
error: cannot invoke 'removeObserver' with an argument list of type '(AnotherClass)'
oldValue.removeObserver(self)
note: overloads for 'removeObserver' exist with these partially matching parameter lists: (NSObject, forKeyPath: String, context: UnsafeMutableRawPointer?), (NSObject, forKeyPath: String)
If the function is called something else, for example helloWorld, the correct error is shown:
error: cannot use mutating member on immutable value: 'oldValue' is immutable
I believe this is an issue which requires attention, because it leads developers to a seriously wrong path when trying to debug the code.
Code is below and in the attached file.
import Foundation
protocol Observable {
associatedtype T
var observers: [T] { get set }
mutating func removeObserver(_ observer: T)
}
extension Observable {
mutating func removeObserver(_ observer: T) {
print("hello world")
}
}
protocol SomeProtocol { }
class SomeClass: Observable {
var observers: [SomeProtocol] = []
}
class AnotherClass: SomeProtocol {
var someObject = SomeClass() {
didSet {
oldValue.removeObserver(self)
someObject.removeObserver(self)
}
}
}
Attachment: Download
Environment
Sierra, Xcode 8.3.1Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug, DiagnosticsQoI, TypeChecker | |Assignee | None | |Priority | Medium | md5: ee5549c90681d2280969444c1e2f80a2Issue Description:
I discovered a confusing bug in the compiler when attempting to modify a member in the didSet observer. This bug requires calling a mutating function on oldValue and it needs to be defined more than once.
In my code, I created an Observable protocol which contains a mutating removeObserver() function. I then have a class which inherits from NSObject (which defines its own removeObserver as part of KVO) and implements my Observable protocol. An instance of this SomeClass is attached to an AnotherClass instance as a member variable.
When attempting to call oldValue.removeObserver() in the didSet of the SomeClass variable, the compiler will throw the following errors:
error: cannot invoke 'removeObserver' with an argument list of type '(AnotherClass)'
oldValue.removeObserver(self)
note: overloads for 'removeObserver' exist with these partially matching parameter lists: (NSObject, forKeyPath: String, context: UnsafeMutableRawPointer?), (NSObject, forKeyPath: String)
If the function is called something else, for example helloWorld, the correct error is shown:
error: cannot use mutating member on immutable value: 'oldValue' is immutable
I believe this is an issue which requires attention, because it leads developers to a seriously wrong path when trying to debug the code.
Code is below and in the attached file.