- Proposal: TBD
- Author: Erica Sadun
- Status: TBD
- Review manager: TBD
This proposal removes setter and observer name overrides from the Swift programming
language, limiting their use to the defaults of newValue
and oldValue
.
Swift-evolution thread: TBD
Swift setters and property observers supply predefined symbols that represent value
arguments. These are newValue
for set
and willSet
, and oldValue
for didSet
.
These implicit names are always available -- you don't need to take any action to have
access to them -- and they are instantly recognizable in context.
Swift allows you to override newValue
and oldValue
by supplying a name
in parentheses after the set
/willSet
/didSet
keyword, for example:
set(temperature) {
// use temperature instead of newValue
}
This feature is an attractive nuisance for the following reasons:
Preferring newValue
and oldValue
to custom names is consistent. Someone reading code needn't recognize a new and unfamiliar symbol in setter or observer context.
Preferring newValue
and oldValue
to custom names avoids errors. Some developers prefer to name all mentioned values for the sake of consistency, clarity, and readability like this:
set(newValue) {...}
Developers who follow this rule may accidentally insert newValue
or oldValue
in the wrong observer. It is not that uncommon. (See this tweet, for example.) Swift does not check for name mismatches, specifically for the common error of using oldValue
in place of newValue
or vice versa.
Upon adopting this proposal:
- Swift removes name overrides from the language.
- Swift allows the current grammar to be used but disallows the mention of any mismatched name:
set { ... } // okay
willSet { ... } // okay
didSet { ... } // okay
set(newValue) { ... } // okay, self-documenting
set(oldValue) { ... } // compiler error
willSet(newValue) { ... } // okay, self-documenting
willSet(oldValue) { ... } // compiler error
didSet(oldValue) { ... } // okay, self-documenting
didSet(newValue) { ... } // compiler error
didSet(bob) { ... } // compiler error
As an optional extra, Swift could emit warnings for any type member named newValue
or oldValue
.
var newValue: T { ... } // warning
A more extreme step would disallow the use of newValue
and oldValue
members, reserving those words for setters and observers. This proposal does not go so far since newValue
and oldValue
are reasonable property names for a generic ChangeSet<T>
struct.
Although a warning could be limited to the presence of property observers and setters, this is not recommended. Deferring warnings until there's a name conflict might introduce the desire to rename members and break APIs when observers and setters are added at a later date. That outcome is undesirable.
Please note that Swift properly differentiates between members (self.newValue
) and the newValue
argument, as in the following example.
struct Foo {
var newValue: Int = 0
var observedMember: Int {
willSet {
print(newValue)
// newValue = 100 // error, `newValue` is immutable
self.newValue = 100
}
}
}
var test = Foo(newValue: 0, observedMember: 50)
test.observedMember = 60 // prints 60
test.newValue // 100
This proposal is breaking. The migrator will need to remove overrides and rename their mentions to newValue
and oldValue
.
This proposal is breaking so needs to be considered in Swift 4 Stage 1
- If this proposal is not adopted, Swift could still warn or error on
set(oldValue)
,willSet(oldValue)
, anddidSet(newValue)
, since these can be considered to be always wrong. - Swift could entirely remove the parentheses syntax, although many developers prefer to explicitly mention the magic argument names.