Proposal: Allow willChange and didChange observers on a property


(Nathan de Vries) #1

It's currently possible to define either or both of the following observers on a property:
willSet, called just before the value is stored
didSet, called immediately after the new value is stored
I'm finding myself using didSet extensively, but almost always guard my didSet with a clause to see if the value has changed:

    class CustomView : UIView {
        var state : CustomViewState = false {
            didSet {
                guard state != oldValue else { return }
                // Act on the new state.
            }
        }
    }

Given the frequency of use, it would be great if I could strip this boilerplate altogether and simply rewrite this as:

    class CustomView : UIView {
        var state : CustomViewState = false {
            didChange {
                // Act on the new state.
            }
        }
    }

Property types conforming to Equatable would be checked for the implicit guard via ==, otherwise it would fall back on the identity operator (===) for value and reference types that don't conform to Equatable.

This would mean the following observers could be defined on a property:
willSet, called just before the value is stored
willChange, called just before the value is stored if the value is different to the previous value
didSet, called immediately after the new value is stored
didChange, called immediately after the new value is stored if the new value is different to the previous value
—Nathan


(Chris Lattner) #2

It's currently possible to define either or both of the following observers on a property:
willSet, called just before the value is stored
didSet, called immediately after the new value is stored

...

This would mean the following observers could be defined on a property:
willSet, called just before the value is stored
willChange, called just before the value is stored if the value is different to the previous value
didSet, called immediately after the new value is stored
didChange, called immediately after the new value is stored if the new value is different to the previous value

I’m open to consider a change along these lines, but the proposal would have to be fleshed out more. Presumably it would only work for equatable types, right? Also, can a property have these observers as well as the existing ones? Would it be possible to add *one of* didChange or willChange - since less is better?

-Chris

···

On Dec 5, 2015, at 4:00 PM, Nathan de Vries via swift-evolution <swift-evolution@swift.org> wrote:


(Mosab Elagha) #3

+1. This feature would allow for a more clean approach in checking the
existing state of a value.

Also, can a property have these observers as well as the existing ones?

I'm not really familiar with the implementation of the observers, but why
wouldn't it be able to? Maybe didSet can precede didChange in order of
execution if both are implemented, so you can have default behavior when
accessing a value but certain other behavior if it has changed. Or maybe
have willChange/didChange be a property that can be accessed within
willSet/didSet (like oldValue).

-Mosab Elagha

···

On Sun, Dec 6, 2015 at 12:11 AM, Chris Lattner via swift-evolution < swift-evolution@swift.org> wrote:

On Dec 5, 2015, at 4:00 PM, Nathan de Vries via swift-evolution < > swift-evolution@swift.org> wrote:

It's currently possible to define either or both of the following
observers on a property:

   - *willSet*, called just before the value is stored
   - *didSet*, called immediately after the new value is stored

...

This would mean the following observers could be defined on a property:

   - *willSet*, called just before the value is stored
   - *willChange*, called just before the value is stored if the value is
   different to the previous value
   - *didSet*, called immediately after the new value is stored
   - *didChange*, called immediately after the new value is stored if the
   new value is different to the previous value

I’m open to consider a change along these lines, but the proposal would
have to be fleshed out more. Presumably it would only work for equatable
types, right? Also, can a property have these observers as well as the
existing ones? Would it be possible to add *one of* didChange or
willChange - since less is better?

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Nathan de Vries) #4

It's currently possible to define either or both of the following observers on a property:
willSet, called just before the value is stored
didSet, called immediately after the new value is stored

...

This would mean the following observers could be defined on a property:
willSet, called just before the value is stored
willChange, called just before the value is stored if the value is different to the previous value
didSet, called immediately after the new value is stored
didChange, called immediately after the new value is stored if the new value is different to the previous value

I’m open to consider a change along these lines, but the proposal would have to be fleshed out more. Presumably it would only work for equatable types, right?

I did a little hand-waving in that direction:

"Property types conforming to Equatable would be checked for the implicit guard via ==, otherwise it would fall back on the identity operator (===) for value and reference types that don't conform to Equatable."

Do you see an issue with falling back on identity if a property's type doesn't conform to Equatable?

Also, can a property have these observers as well as the existing ones?

I don't see any issue with someone deciding to exhaustively add all observers to a property, but practically I'd only expect a subset (one) of them to be implemented. In my case I'd almost exclusively use didChange.

Would it be possible to add *one of* didChange or willChange - since less is better?

I never use willSet at the moment and can't imagine myself using willChange, so it was really only included for completeness. I'd be fine with limiting the addition to didChange only, with my only concern being the inconsistency of not providing willChange.

—Nathan

···

On Dec 5, 2015, at 10:11 PM, Chris Lattner <clattner@apple.com> wrote:

On Dec 5, 2015, at 4:00 PM, Nathan de Vries via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:


(Chris Lattner) #5

+1. This feature would allow for a more clean approach in checking the existing state of a value.

> Also, can a property have these observers as well as the existing ones?

I'm not really familiar with the implementation of the observers, but why wouldn't it be able to? Maybe didSet can precede didChange in order of execution if both are implemented, so you can have default behavior when accessing a value but certain other behavior if it has changed. Or maybe have willChange/didChange be a property that can be accessed within willSet/didSet (like oldValue).

I believe it is possible to implement, I’m just trying to give guidance on the sorts of things a formal proposal should address.

-Chris

···

On Dec 5, 2015, at 10:42 PM, Mosab Elagha <elagha2@illinois.edu> wrote:

-Mosab Elagha

On Sun, Dec 6, 2015 at 12:11 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 5, 2015, at 4:00 PM, Nathan de Vries via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

It's currently possible to define either or both of the following observers on a property:
willSet, called just before the value is stored
didSet, called immediately after the new value is stored

...

This would mean the following observers could be defined on a property:
willSet, called just before the value is stored
willChange, called just before the value is stored if the value is different to the previous value
didSet, called immediately after the new value is stored
didChange, called immediately after the new value is stored if the new value is different to the previous value

I’m open to consider a change along these lines, but the proposal would have to be fleshed out more. Presumably it would only work for equatable types, right? Also, can a property have these observers as well as the existing ones? Would it be possible to add *one of* didChange or willChange - since less is better?

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Hart) #6

Chris, wouldn't that be better designed/implemented with the property delegate functionality Joe Groff is working on?

···

On 06 Dec 2015, at 07:52, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 5, 2015, at 10:42 PM, Mosab Elagha <elagha2@illinois.edu> wrote:

+1. This feature would allow for a more clean approach in checking the existing state of a value.

> Also, can a property have these observers as well as the existing ones?

I'm not really familiar with the implementation of the observers, but why wouldn't it be able to? Maybe didSet can precede didChange in order of execution if both are implemented, so you can have default behavior when accessing a value but certain other behavior if it has changed. Or maybe have willChange/didChange be a property that can be accessed within willSet/didSet (like oldValue).

I believe it is possible to implement, I’m just trying to give guidance on the sorts of things a formal proposal should address.

-Chris

-Mosab Elagha

On Sun, Dec 6, 2015 at 12:11 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 5, 2015, at 4:00 PM, Nathan de Vries via swift-evolution <swift-evolution@swift.org> wrote:

It's currently possible to define either or both of the following observers on a property:
willSet, called just before the value is stored
didSet, called immediately after the new value is stored

...

This would mean the following observers could be defined on a property:
willSet, called just before the value is stored
willChange, called just before the value is stored if the value is different to the previous value
didSet, called immediately after the new value is stored
didChange, called immediately after the new value is stored if the new value is different to the previous value

I’m open to consider a change along these lines, but the proposal would have to be fleshed out more. Presumably it would only work for equatable types, right? Also, can a property have these observers as well as the existing ones? Would it be possible to add *one of* didChange or willChange - since less is better?

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(plx) #7

All else aside, isn’t `willChange` semantically-problematic anyways, due to it being possible to override `set` to modify the value that gets stored?

EG:

    class X {
      var font: UIFont {
         willChange {
           self.delegate?.fontWillChange(
            fromFont: oldValue,
            toFont: newValue
           )
         }
      }
    }

    class Y : X {
      override var font: UIFont {
        set {
           super.font = self.adjustedFontForBaseFont(newValue)
           // ^ e.g. to enforce monospace-digits trait
        }
      }
    }

…which isn't the nicest thing to do, but can be the easiest way to customize some of the UI widgets’ behavior.

···

On Dec 6, 2015, at 11:28 PM, Nathan de Vries via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 5, 2015, at 10:11 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Dec 5, 2015, at 4:00 PM, Nathan de Vries via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

It's currently possible to define either or both of the following observers on a property:
willSet, called just before the value is stored
didSet, called immediately after the new value is stored

...

This would mean the following observers could be defined on a property:
willSet, called just before the value is stored
willChange, called just before the value is stored if the value is different to the previous value
didSet, called immediately after the new value is stored
didChange, called immediately after the new value is stored if the new value is different to the previous value

I’m open to consider a change along these lines, but the proposal would have to be fleshed out more. Presumably it would only work for equatable types, right?

I did a little hand-waving in that direction:

"Property types conforming to Equatable would be checked for the implicit guard via ==, otherwise it would fall back on the identity operator (===) for value and reference types that don't conform to Equatable."

Do you see an issue with falling back on identity if a property's type doesn't conform to Equatable?

Also, can a property have these observers as well as the existing ones?

I don't see any issue with someone deciding to exhaustively add all observers to a property, but practically I'd only expect a subset (one) of them to be implemented. In my case I'd almost exclusively use didChange.

Would it be possible to add *one of* didChange or willChange - since less is better?

I never use willSet at the moment and can't imagine myself using willChange, so it was really only included for completeness. I'd be fine with limiting the addition to didChange only, with my only concern being the inconsistency of not providing willChange.

—Nathan
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #8

Yes, it that proposal is capable of expressing this, then that is how I would prefer property observers in general to work.

-Chris

···

On Dec 6, 2015, at 3:27 AM, David Hart <david@hartbit.com> wrote:

Chris, wouldn't that be better designed/implemented with the property delegate functionality Joe Groff is working on?

On 06 Dec 2015, at 07:52, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 5, 2015, at 10:42 PM, Mosab Elagha <elagha2@illinois.edu> wrote:

+1. This feature would allow for a more clean approach in checking the existing state of a value.

> Also, can a property have these observers as well as the existing ones?

I'm not really familiar with the implementation of the observers, but why wouldn't it be able to? Maybe didSet can precede didChange in order of execution if both are implemented, so you can have default behavior when accessing a value but certain other behavior if it has changed. Or maybe have willChange/didChange be a property that can be accessed within willSet/didSet (like oldValue).

I believe it is possible to implement, I’m just trying to give guidance on the sorts of things a formal proposal should address.

-Chris

-Mosab Elagha

On Sun, Dec 6, 2015 at 12:11 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 5, 2015, at 4:00 PM, Nathan de Vries via swift-evolution <swift-evolution@swift.org> wrote:

It's currently possible to define either or both of the following observers on a property:
willSet, called just before the value is stored
didSet, called immediately after the new value is stored

...

This would mean the following observers could be defined on a property:
willSet, called just before the value is stored
willChange, called just before the value is stored if the value is different to the previous value
didSet, called immediately after the new value is stored
didChange, called immediately after the new value is stored if the new value is different to the previous value

I’m open to consider a change along these lines, but the proposal would have to be fleshed out more. Presumably it would only work for equatable types, right? Also, can a property have these observers as well as the existing ones? Would it be possible to add *one of* didChange or willChange - since less is better?

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution