# SE-0268 (Review #2) — Review didSet Semantics

**URL:** <https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396>\
**Category:** Proposal Reviews\
**Created:** [December 6, 2019, 12:15am UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396 "2019-12-06T00:15:49Z")\
**Posts on this page:** 20\
**Page:** 5

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [December 8, 2019, 7:00pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/81 "2019-12-08T19:00:54Z")

</div>

> [@James\_Dempsey](#):
>
> Because in your brief description of the the feature, I had thought that the `set` block you described could be added anywhere within the struct or class definition, which would mean needing to look through the entire struct or class to see if that overriding behavior had been added.

But don’t worry, most `set` blocks shouldn’t be more than a few lines and would be defined very close to the member declaration, just like most `didSet` blocks!

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [December 8, 2019, 8:35pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/82 "2019-12-08T20:35:54Z")

</div>

> [@xwu](#):
>
> If you both support the change in semantics, and do not support changing syntax for the current behavior, then you must come out against any attempt to distinguish the two semantics at all.

Isn't that a [False Dilemma](https://en.wikipedia.org/wiki/False_dilemma)? There are numerous ways you can distinguish the semantics, the _most aggressive_ of which is requiring new syntax.

IMO the "right" way to notify users for something this in the weeds that will affect so few people is with documentation. The problem is, the most popular tooling (Xcode) for Swift has no accessible documentation for _either_ `didSet` or `oldValue`. _That's_ the problem I think needs to be addressed.

Keep in mind, the goal is "to avoid confusion as to when the getter is called or not". To me, having a parameter does not, on it's own, indicate that kind of a semantic difference. If that's true of most users they will _still_ have to read the documentation in order to know about the difference. Yes, requiring the named parameter will make it obvious when that's specifically what's being looked for, but how often will that happen?

It's a corner case to use `oldValue` (6% according to @suyashsrijan: [SE-0268 (Review #2) — Review didSet Semantics - #49 by suyashsrijan](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/49)), IME it's a corner case for `oldValue` to be used for anything other than a check for `didChange`, and it's a corner case of _that_ where this semantic difference would cause a problem. So, this deprecation would make 6% of `didSet` usage more verbose, to indicate a difference that will only matter to...I'll say 0.1%, (though it's probably even smaller). And even in that case they will _still_ have to manually find the documentation for these semantics.

---

<div class="post-metadata">

**Author:** ![Avi](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/avi/32/2962_2.png) [@Avi](https://forums.swift.org/u/Avi)\
**Post date:** [December 8, 2019, 8:38pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/83 "2019-12-08T20:38:14Z")

</div>

> [@xwu](#):
>
> The motivation is to allow users more easily to distinguish the two behaviors.

I don't understand why we need to change code to distinguish between these behaviors. If `didSet` uses `oldValue`, the getter is invoked. If not, it's not. That should be simple enough to learn and/or document. Especially if we consider the current behavior to be a bug.

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [December 8, 2019, 9:30pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/84 "2019-12-08T21:30:48Z")

</div>

I think Swift aims to favour clarity over brevity, and being more explicit in case of `oldValue` _specifically_ doesn't seem to have any harm.

> [@Pitch: didSet Semantics](https://forums.swift.org/t/pitch-didset-semantics/27858/69):
>
> I don't understand the undercurrent of your question. Are you saying that didset() or didset(oldvalue) is onerous to write or difficult to understand? Accessors aren't that common and are not important to sugar at this level (imo) given the semantic issues that sugar raises. I'd rather have the behavior be explicit - this makes it easier to reason about.

In the pitch thread, it was also mentioned that this should've been the case since day 1. However, we do have an opportunity to fix that right now if we want to. I would be interested in knowing if people are willing to change their opinion if we also update code completion as a follow-up improvement. I think that once that is fixed then people will feel a bit different about the whole thing because you won't have to write it out manually each time (if you even run into that situation, which is not that common, at least according to my [research](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/49)). Of course, people who think there is a lot of value of having implicit `oldValue` are not going to be persuaded by changes to tooling.

---

<div class="post-metadata">

**Author:** ![beccadax](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/beccadax/32/34217_2.png) [@beccadax](https://forums.swift.org/u/beccadax)\
**Post date:** [December 8, 2019, 9:57pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/85 "2019-12-08T21:57:16Z")

</div>

> [@xwu](#):
>
> It's not so much about the "you" who is "explicitly typing," but the many "yous" who will have to read and understand the meaning of code they didn't type. That the semantics meaning of `didSet` changes based on how it's implemented makes it harder to reason about.

This sounds to me like an excellent rationale for a linter setting or style guide rule requiring you to explicitly declare `oldValue`. But I don’t think it reaches the level of necessity to warrant a warning.

---

<div class="post-metadata">

**Author:** ![Samasaur](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/samasaur/32/8344_2.png) [@Samasaur](https://forums.swift.org/u/Samasaur)\
**Post date:** [December 8, 2019, 10:14pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/86 "2019-12-08T22:14:05Z")

</div>

I'm +1 for the bug fix, but -1 for the deprecation of the implicit `oldValue`. Here's how I'm looking at it:

- Not using the implicit `oldValue` and not declaring any explicit arguments implies (correctly, now) that the getter will not be called
- Using `oldValue` or another argument in the body of `didSet` makes it pretty clear that the getter is being called (whether or not the argument was explicitly declared)
- Declaring an explicit argument but not using it, when done intentionally and looked at after reading this thread, makes sense to have the getter be called, but _does not make sense without the context of this thread._ If I were to read this in anyone's code (including my own), I would have thought it slipped their mind and was a mistake.
- Being forced to ensure that an argument is explicitly declared if I am to use it but not declared if I am not using it (so that the getter is not called) seems like a recipe for disaster, at least for me personally.

The gist of this is that if the implicit `oldValue` is not deprecated, developers have a _choice_ on whether or not they'd like to use an explicit `didSet(oldValue)`, while if it is deprecated we are forcing every developer to do something that a large amount of people clearly don't want to do.

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [December 8, 2019, 10:23pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/87 "2019-12-08T22:23:42Z")

</div>

> [@Samasaur](#):
>
> Declaring an explicit argument but not using it, when done intentionally and looked at after reading this thread, makes sense to have the getter be called, but _does not make sense without the context of this thread._ If I were to read this in anyone's code (including my own), I would have thought it slipped their mind and was a mistake

That’s an interesting observation. One instance would be an empty `didSet`, but I suppose this would be pretty rare in practice (and really something that a power user would use for something very specific), but still, seeing an empty `didSet` would definitely look like a mistake if someone didn’t know that it was calling the getter. I think the difference would be in the explicit-ness of that (i.e `didSet(oldValue)` {} vs `didSet {}` - which one makes it explicit that the getter is called?).

---

<div class="post-metadata">

**Author:** ![QuinceyMorris](https://avatars.discourse-cdn.com/v4/letter/q/d26b3c/32.png) [@QuinceyMorris](https://forums.swift.org/u/QuinceyMorris)\
**Post date:** [December 8, 2019, 10:32pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/88 "2019-12-08T22:32:15Z")

</div>

> [@xwu](#):
>
> If you both support the change in semantics, and do not support changing syntax for the current behavior, then you must come out against any attempt to distinguish the two semantics at all.

Would you mind clarifying what you mean by "changing syntax" here?

It seems to me that this discussion has come down to deciding between two alternatives:

1. Invoking the getter depends on the presence of the "didSet(xxx)" syntax, where the parentheses are the important part and the name inside them is immaterial.

2. Invoking the getter depends on the presence of the "xxx" variable in the body of the accessor, where the occurrence of the name is the important part, and it is immaterial what determines the name (implicit or explicit declaration).

To me, these are both "syntax", and the alternatives are between changing what the relevant syntax is (#1), and changing what the existing syntax indicates (#2). Both of those could plausibly be described as "changing syntax".

FWIW, my vote is currently for option #2, because I haven't yet seen a compelling reason to adopt #1.

_edited to fix typo "setter" for "getter"_

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [December 8, 2019, 10:43pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/89 "2019-12-08T22:43:57Z")

</div>

> [@suyashsrijan](#):
>
> However, we do have an opportunity to fix that right now if we want to. I would be interested in knowing if people are willing to change their opinion if we also update code completion as a follow-up improvement. I think that once that is fixed then people will feel a bit different about the whole thing because you won't have to write it out manually each time

If the idea is to start the process of de-sugaring accessors (please don't 😇), IMO that should be a separate pitch that includes all of them. It's a significant change in direction that shouldn't be evaluated as a knock-on feature of another pitch. Regardless of the original intention, there are now several years of trends and norms to be taken into consideration that affect that decision.

As mentioned previously, the tooling around this needs improvement regardless of this pitch. If we're taking such improvements into account, I think it makes more sense for this be evaluated after the new tooling is in place, not before.

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [December 8, 2019, 10:52pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/90 "2019-12-08T22:52:39Z")

</div>

I mean, the tooling changes I suggested are something that should’ve been done a long time ago and it’s incremental work that I think should be done regardless of whether we deprecate the implicit `oldValue` or not. Here’s one such recent change related to `didSet`: [[CodeCompletion] Suggest the property name in its didSet clause by rintaro · Pull Request #28319 · apple/swift · GitHub](https://github.com/apple/swift/pull/28319)

The way I think it would work is that when you start to write `didSet`, code completion is going to offer two suggestions: one with a parameter name and one without.

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [December 8, 2019, 11:15pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/91 "2019-12-08T23:15:02Z")

</div>

> [@suyashsrijan](#):
>
> Here’s one such recent change related to `didSet` : [https://github.com/apple/swift/pull/28319](https://github.com/apple/swift/pull/28319)

Yasss that's been bugging me the last few weeks!

> [@suyashsrijan](#):
>
> The way I think it would work is that when you start to write `didSet` , code completion is going to offer two suggestions: one with a parameter name and one without.

Yes! this should be done (for all accessors) regardless of this pitch. It wouldn't surprise me if some users don't even know you can have a custom name for `oldValue`.

The completion should also add the (_always required_) new code block. Right now it just completes the name.

What I would _really_ love is to be able to start writing `didSet` after a property and have code completion give the option to add the whole expression!

---

<div class="post-metadata">

**Author:** ![michelf](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/michelf/32/1180_2.png) [@michelf](https://forums.swift.org/u/michelf)\
**Post date:** [December 9, 2019, 12:35am UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/92 "2019-12-09T00:35:24Z")

</div>

Assuming after all this discussion the Core Team still decides to go ahead with the syntax change, I'd like to suggest making the warning more symmetrical:

```swift
didSet {
   log(oldValue) // warning: oldValue not declared, consider adding declaration
}

```

So it makes you add the declaration. And then later you remove `oldValue` from the body so you get:

```swift
didSet(oldValue) { // warning: oldValue is never used, consider removing it
   log("boo!")
}

```

This is similar to the `var` / `let` fix-it that depend on whether you mutate a local variable; it goes in both directions.

If you really need to trigger the getter but not use the value, this is how you can avoid the warning:

```swift
didSet(oldValue) {
   _ = oldValue // triggering the getter, no warning
}

```

This could be an alternative fix-it when `oldValue` is declared but unused.

I'm still of the opinion that implicit `oldValue` should not be deprecated. But I think the approach above is better than what is currently in the proposal. In particular you'll get reminded when the declaration becomes unnecessary after you remove `oldValue` from the body. It could also apply nicely everywhere else we have implicit declarations of this kind, if it ever comes to that.

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [December 9, 2019, 5:24pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/93 "2019-12-09T17:24:05Z")

</div>

Yeah, that sounds like a reasonable tweak to how the new warnings work.

---

<div class="post-metadata">

**Author:** ![wilshipley](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wilshipley/32/10165_2.png) [@wilshipley](https://forums.swift.org/u/wilshipley)\
**Post date:** [December 10, 2019, 12:42am UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/94 "2019-12-10T00:42:20Z")

</div>

I love the proposal, but I’m not a fan of `didSet(oldValue)` nor deprecating `didSet` raw when it uses `oldValue`.

The former seems unnecessarily wordy and raises questions for me (can I use a different identifier than `oldValue`?) and screws up the symmetry with `willSet`’s `newValue`.

As near as I can tell the only reason to have the `didSet(oldValue)` form is to tell the programmer “Hey you’ll be calling the `oldValue` here that might be slow,” except it’ll be no slower than it was before this change was made, and we’d have to live with this syntax forever.

Also `oldValue` just seems like a bizarre thing to call out. I can’t think of other places in Swift where you have to mention some variable in order to tell the compiler you understand and consent to it being slightly slower.

Note also that the only case in which this proposal might cause some source breakage (someone was crazily relying on fetching `oldVaue` and some side effect of it) is NOT addressed at all by the user seeing `didSet(oldValue)` — that just tells them it definitely WILL be fetched. So we’re asking the user to learn something new (eg, `didSet(oldValue)`) in order to work around a possible but very unlikely source-breaking change, but if the user has to learn something new to work around this change, why not have the new thing be “hey `didSet` has different semantics” instead of “hey `didSet` has a new spelling for your case?”

The same thinking applies to why we shouldn’t warn if the user doesn’t use `didSet(oldValue)` but accesses `oldValue` — I think the former is wordy and silly and ugly and useless (the latter based on my possibly-flawed understanding of its creation) so there’s no need to deprecate raw `didSet` in the “use `oldValue`” case. Just skip the adding former.

-Wil Shipley  
Chief Monster

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [December 10, 2019, 1:46am UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/95 "2019-12-10T01:46:22Z")

</div>

`didSet(oldValue)` is not _new_ - you can write it today (and yes, you can swap `oldValue` with any other identifier).

The problem with `didSet` is unique, so while it does screw the symmetry, it’s also (probably) not a good idea to change the rest because of it (as they don’t have the same problem).

I think it boils down to how the semantics is communicated to _anyone_ reading the code. With `didSet(oldValue)`, it’s clear that the `oldValue` is fetched and with `didSet` it’s clear that the `oldValue` is not fetched. You don’t have to read a special section of the Swift documentation to realize that. A lot of people were already unaware that the `oldValue` was always being fetched, even when unused. So, being explicit can help make that thought go away and reduce the chances of confusion.

Some people prefer the _presence_ of `oldValue` in the body to be the thing that communicates the semantics. I don’t know what the _right_ way is, but I also don’t see any harm in being explicit. Anyway, this has been discussed in-depth in this thread, so it really depends on whether you find value in the explicitness (while keeping it mind that the semantics are changing) or whether you find it “noise” and would rather keep using the implicit `oldValue`.

I think we’ve all expressed our opinions and it’s up to the Core Team now to decide whether to deprecate or not.

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [December 10, 2019, 5:36am UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/96 "2019-12-10T05:36:16Z")

</div>

Btw, I’m still confused about how `willSet` evades this treatment.

It doesn’t have any benefit for `set` operation, but it’d have some optimization benefit for `modify` operation, no?

Esp. if we do partial-modification to the variable

If we have `willSet` with `newValue` then it would force the operation to hold both versions of variable, preventing in-place partial modification.

```swift
var observed: ... {
  willSet {
    // `observed` & `newValue` must be separated instances
    // Can’t mutate in-place
    print(observed, newValue)
  }
}

```

So even if we mutate a very small chunk of `observed` it is forced to copy an entirely new value into `newValue`.

```swift
// This cause CoW to `observed`,
// even if we only modify `partial`
a.observed.partial = ...

```

Previous discussions seem to apply to assignment, but I don’t see how it applies to partial modification.

Or am I missing something 🤔.

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [December 10, 2019, 7:47am UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/97 "2019-12-10T07:47:51Z")

</div>

There are two ways to give `willSet` semantics for a non-instantaneous modification (e.g. calling a `mutating` method on the property):

- You can do what Swift does today, which is to force the modification to happen to a temporary copy and then call `willSet` immediately before writing back.
- You can call `willSet` before the modification begins.

The second makes more sense to me abstractly, but it's totally incompatible with `willSet` getting passed the new value, and it's a radically different point in the execution of the program than the first (in our example of a `mutating` method, either before the call or after it). It would be unacceptable for the timing of the call to `willSet` to shift this much based only on whether `newValue` was used in the body. So we're locked into the first option.

There's really no way to optimize `willSet` given those semantics; it has to make a copy.

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [December 10, 2019, 1:23pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/98 "2019-12-10T13:23:45Z")

</div>

I'm in favour of this change and deprecating implicit `oldValue`.

I think this meets the bar needed for a "source-breaking" change (it isn't really source breaking IMO, it just produces a warning for the now-deprecated thing). C++ does similar things from time to time - one of the projects I'm working on now is getting warnings saying `'register' storage class specifier is deprecated and incompatible with C++17` from a 3rd-party dependency (even though we're compiling in C++11 mode).

Just like Clang still compiles that code with `register` in it, we will still compile code with implicit `oldValue` in compatibility mode, so I don't think this is such a big deal or anything developers aren't used to handling. That's not to say we should make a habit of it.

---

<div class="post-metadata">

**Author:** ![Avi](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/avi/32/2962_2.png) [@Avi](https://forums.swift.org/u/Avi)\
**Post date:** [December 10, 2019, 1:33pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/99 "2019-12-10T13:33:09Z")

</div>

I am in favor of the behavioral change, but I am not in favor of deprecating implicit `oldValue`. I have not heard an argument for why it is actively harmful, and I don't see the value in adding warnings for code that is not at all incorrect.

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [December 10, 2019, 5:09pm UTC](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396/100 "2019-12-10T17:09:41Z")

</div>

> [@Karl](#):
>
> it isn't really source breaking IMO, it just produces a warning for the now-deprecated thing

If it's deprecated, it will be removed in a future version. It's not source breaking _currently_, (though to some warning == error), but it will be in future. My guess is that would happen with Swift 6.0, but that's likely yet to be determined.

My understanding is C++''s version usage is pretty fragmented and high adoption of the latest version takes several years. IME Swift version adoption is incomparably faster 🙂

[Previous page](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396.md?page=4)

[Next page](https://forums.swift.org/t/se-0268-review-2-review-didset-semantics/31396.md?page=6)
