Allow properties with a didSet or willSet to be assigned to themselves

Consider this example:

class C {
  var p = 123 { didSet { print("trigger some effect with \(p)") } }
}
let c = C()
c.p = c.p // error: assigning a property to itself

Given the didSet, ie that an assignment is meant to trigger some effect with \(p), it seems strange that this should be an error, or even a warning.

Put another way: The compiler currently prevents us from using the most natural way to express "trigger some effect with an unmodified value", and instead forces us to jump through hoops like …

… these.
let cp = c.p
c.p = cp

or

c.p = (c.p, ()).0

or

c.p = { $0 }(c.p)

or

c.p = c.p + 0

This last one only happens to work for this particular example (because p happens to be Int), of course.


So, would it make sense to not issue this error for properties that have a didSet or willSet?

I would argue that the most natural way to express "trigger some effect" is a function call, and you should refactor your code.

refreshScreen() is much more readable way to trigger a screen refresh than screenWidth = screenWidth for example

1 Like

Isn't this the same as arguing against the existence of didSet / willSet in the language?

And to be clear, I interpret your "trigger some effect", as "trigger some effect when this property is assigned", which is what this thread is about.


I don't see how this example is relevant to the pitch/question.

An attempt to make it relevant:

class ViewModel {
  private var state = .initialState {
    didSet { refreshScreen(withViewModelState: state) }
  }
  ...

The question then becomes: Why should the compiler prevent me from using "state = state" within my view model as a way to tell the view to refresh itself with the same state that the view model already has?

And now I think I get what you meant, and that you are right, because I guess the answer could be that
state = state
makes a lot less sense than eg
refreshScreen(withViewModelState: state)

:slight_smile:

1 Like

There are two perspectives here, the author of ViewModel and the user of ViewModel

From the perspective of the author of ViewModel, it's fine and dandy to use didSet and willSet to trigger some effect when this property is assigned, for example to make sure the screen is in sync with the properties. You just have to keep in mind that the change of the property is the main effect, and refreshing the screen is a side effect.

From the perspective of the user there are two things they may want to do.

  • change the state to foo - in this case they should write state = foo. In this case the main effect is the change of the property. User shouldn't have to worry if it triggers some side effects or not.
  • refresh the screen because it got out of sync for some reason - in this case the state property is totally unrelated to what they want to do. If state = state is the solution they reach for, it means that the abstraction is very leaky :P

I'm not 100% sure if compiler should prevent you from using state = state, but I'm 100% sure the linter should.

2 Likes
Terms of Service

Privacy Policy

Cookie Policy