Skip to content

Add didSet/willSet recursion change to the changelog #15526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 27, 2018

Conversation

hamishknight
Copy link
Contributor

In #15280 we changed the behaviour of setting a property within its own didSet or willSet observer, such that we only perform direct accesses on self in Swift 5 mode.

This commit adds this to the changelog and, in addition, does some gardening for the SR links.

@jrose-apple
Copy link
Contributor

Please mention that this only happens in Swift 5 mode. (Being in the Swift 5 section isn't enough to imply that.)

@hamishknight hamishknight force-pushed the didset-recursion-changelog branch from be05e5d to 17407a8 Compare March 26, 2018 22:56
In swiftlang#15280 we changed the behaviour of setting a property within its own `didSet` or `willSet` observer, such that we only perform direct accesses on `self` in Swift 5 mode.

This commit adds this to the changelog and, in addition, does some gardening for the SR links.
@hamishknight hamishknight force-pushed the didset-recursion-changelog branch from 17407a8 to 96c3296 Compare March 26, 2018 22:56
@jrose-apple
Copy link
Contributor

@swift-ci Please smoke test and merge

@hamishknight
Copy link
Contributor Author

@jrose-apple Looks like that didn't trigger the bot for some reason; could you please try again?

@jrose-apple
Copy link
Contributor

@swift-ci Please smoke test and merge

@jrose-apple jrose-apple self-assigned this Mar 27, 2018
@swift-ci swift-ci merged commit b6f94a3 into swiftlang:master Mar 27, 2018
@hamishknight hamishknight deleted the didset-recursion-changelog branch March 27, 2018 22:48
@afshinpir
Copy link

afshinpir commented Jan 4, 2019

@jrose-apple This and #15280 causes strange results in Swift 4.2. You fell in infinite loop in a lot of strange cases.
I have already posted in stackoverflow regarding this problem.
It would be great if you elaborate exactly what should be correct behavior regarding setting value of a property within its own didSet.

@hamishknight
Copy link
Contributor Author

@afshinpir This change is unrelated to the behaviour that you're experiencing in your Stack Overflow question – you'd also get the same behaviour in Swift 4.1.

Whether or not a property is accessed directly (without triggering observers) is determined statically by the context in which the access is performed, rather than being determined dynamically by whether or not it's taking place during a call to a given function.

The current behaviour (up until Swift 5 mode) is to always perform a direct access when accessing a property within its own didSet/willSet observer. The change introduced in the linked patch restricts this behaviour to only apply when it's a property access that is taking place on self, and this new behaviour will take effect in Swift 5 mode.

However in either case, a property access done within an instance method will not be done directly, which is the behaviour you're observing.

@afshinpir
Copy link

afshinpir commented Jan 4, 2019

@hamishknight But when we are setting property within its own didSet, I think it should not trigger even if we are using an instance method. Assume there is a lot of codes in didSet and we want to organize them into few methods. If there is a decision not to trigger didSet when we set property inside it, I think it should be similar in all cases, either with setting it inside didSet itself or by calling another function. And as a suggestion, maybe it is better that trigger didSet or not depend on type data. For example, does not trigger for reference types and trigger it for value types.

@jrose-apple
Copy link
Contributor

Meta-comment: this sort of discussion is better held on the forums at https://forums.swift.org. Other interested parties won't know to look here.

@hamishknight
Copy link
Contributor Author

Sorry, I was going to reply to this sooner but never got around to it. As Jordan says, this discussion would be better placed on the Swift forums. In addition, I'm pretty sure such a change would need to go through evolution.

In short though, my personal feeling is that such a change isn't worth the complexity. I don't think having to split observer implementations up into multiple methods such that those methods need direct access to storage is that common of an occurrence.

It's worth noting you can always forward on direct-to-storage access using an inout parameter:

struct S {
  var i: Int = 0 {
    didSet {
      doSomething(&i)
    }
  }
  private func doSomething(_ i: inout Int) {
    // Work with `i` direct-to-storage.
  }
}

In addition, if needed you can always desugar an observable stored property into a computed property backed by storage, which gives you precise control over when you want the observer to be called.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants