[Discussion] Allow injection of `didSet` and `willSet`


(Adrian Zubarev) #1

Hello dear Swift community, I’m not sure if this was discussed before or not, but I really want to know if something like this is welcome for the future Swift version. If this topic was already discussed, I’m apologizing for bringing it back to life in a new thread.

Lets say I’ve got a third party module and I want to know when the a variable of some type has changed:

extension UIViewController {
     
    public override var view: UIView {
         
        willSet {
            // do something useful here
        }
         
        didSet {
            // do something useful here
        }
    }
}
Wouldn’t be handy to inject custom didSet and willSet functions into any property or computed property?

This would also allow us to build a proper two-way-binding mechanism.

···

--
Adrian Zubarev
Sent with Airmail


(Leonardo Pessoa) #2

+1. This would allow us to create observers on any foreign variable. I'm
far from a compiler right now but I wouldn't this syntax create a new
variable instead of observing an existing one? Even if not, by reading
this one could be mislead to believe so. Perhaps you should give it
something to differentiate from creating a new var, for example by
suppressing the type on this declaration.

···

On Friday, 8 July 2016, Adrian Zubarev via swift-evolution < swift-evolution@swift.org> wrote:

Hello dear Swift community, I’m not sure if this was discussed before or
not, but I really want to know if something like this is welcome for the
future Swift version. If this topic was already discussed, I’m apologizing
for bringing it back to life in a new thread.

Lets say I’ve got a third party module and I want to know when the a
variable of some type has changed:

extension UIViewController {

    public override var view: UIView {

        willSet {
            // do something useful here
        }

        didSet {
            // do something useful here
        }
    }
}

Wouldn’t be handy to inject custom didSet and willSet functions into any
property or computed property?

This would also allow us to build a proper two-way-binding mechanism.

--
Adrian Zubarev
Sent with Airmail

--
L


(Adrian Zubarev) #3

Thats a good point!

Here is some bikeshedding:

public extension UIViewController {
      
    observe public var view: UIView {
          
        willSet {
            // do something useful here
        }
          
        didSet {
            // do something useful here
        }
    }
}
An extra observe keyword might signal to the compiler the correct intended usage.

···

--
Adrian Zubarev
Sent with Airmail

Am 8. Juli 2016 um 13:14:38, Leonardo Pessoa (me@lmpessoa.com) schrieb:

+1. This would allow us to create observers on any foreign variable. I'm far from a compiler right now but I wouldn't this syntax create a new variable instead of observing an existing one? Even if not, by reading this one could be mislead to believe so. Perhaps you should give it something to differentiate from creating a new var, for example by suppressing the type on this declaration.

On Friday, 8 July 2016, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:
Hello dear Swift community, I’m not sure if this was discussed before or not, but I really want to know if something like this is welcome for the future Swift version. If this topic was already discussed, I’m apologizing for bringing it back to life in a new thread.

Lets say I’ve got a third party module and I want to know when the a variable of some type has changed:

extension UIViewController {
      
    public override var view: UIView {
          
        willSet {
            // do something useful here
        }
          
        didSet {
            // do something useful here
        }
    }
}
Wouldn’t be handy to inject custom didSet and willSet functions into any property or computed property?

This would also allow us to build a proper two-way-binding mechanism.

--
Adrian Zubarev
Sent with Airmail

--
L


(Tino) #4

There are (were?) plans for generalized property behaviors; those would be used to implement lazy, as well as didSet/willSet, and could incorporate many other things (including injection)

Of course, an option to observe variables would be handy — but there's always a price to pay, and you'll at least need a way to opt-out: Even if you actually don't observe a property that changes hundreds of times per second, the hooks alone could degrade performance (it's another question if it's wise to have such properties :wink:

Tino


(Adrian Zubarev) #5

I also would like to mention a problem I see with this ‘feature’.

Lets say this is my module:

public struct A {
     
    public var member1: Int = 42
     
    public var member2: Int = 0 {
         
        didSet {
             
            self.member1 = self.member2
        }
    }
}
From a different project, that contains our module we want to observe the public properties:

public extension A {
     
    observe public var member1: Int {
         
        didSet {
            // will be called first
        }
    }
     
    observe public var member2: Int {
         
        didSet {
            // will be called last
        }
    }
}

var a = A()
a.member1 // 42
a.member2 // 0

a.member2 = 100
a.member1 // 100
a.member2 // 100
It’s clear that we should decide on when our observer will be executed. In the example from above I pretended that my observer will be executed after the observer from the module itself.

When we set a.member2 the observer for member1 on our side will be called first, follows by member2 observer, which ‘might’ not be what we need.

I’d suggest that if this ‘feature’ might ever be considered for Swift that we should be able to set the execution order.

Bikeshedding:

observe(first) // called before observer from the module are called
observe(last) // called after the observer from the module where called

···

--
Adrian Zubarev
Sent with Airmail

Am 8. Juli 2016 um 13:22:45, Adrian Zubarev (adrian.zubarev@devandartist.com) schrieb:

Thats a good point!

Here is some bikeshedding:

public extension UIViewController {
       
    observe public var view: UIView {
           
        willSet {
            // do something useful here
        }
           
        didSet {
            // do something useful here
        }
    }
}
An extra observe keyword might signal to the compiler the correct intended usage.

--
Adrian Zubarev
Sent with Airmail

Am 8. Juli 2016 um 13:14:38, Leonardo Pessoa (me@lmpessoa.com) schrieb:

+1. This would allow us to create observers on any foreign variable. I'm far from a compiler right now but I wouldn't this syntax create a new variable instead of observing an existing one? Even if not, by reading this one could be mislead to believe so. Perhaps you should give it something to differentiate from creating a new var, for example by suppressing the type on this declaration.

On Friday, 8 July 2016, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:
Hello dear Swift community, I’m not sure if this was discussed before or not, but I really want to know if something like this is welcome for the future Swift version. If this topic was already discussed, I’m apologizing for bringing it back to life in a new thread.

Lets say I’ve got a third party module and I want to know when the a variable of some type has changed:

extension UIViewController {
       
    public override var view: UIView {
           
        willSet {
            // do something useful here
        }
           
        didSet {
            // do something useful here
        }
    }
}
Wouldn’t be handy to inject custom didSet and willSet functions into any property or computed property?

This would also allow us to build a proper two-way-binding mechanism.

--
Adrian Zubarev
Sent with Airmail

--
L


(Adrian Zubarev) #6

True story, if you’re doing something heavy and there are tons of calls from your observed property you’d pay with a huge performance decrease. Personally I don’t feel like this would be something that stays in the way of having this handy feature, because it’s always up to us to balance the performance of our application.

···

--
Adrian Zubarev
Sent with Airmail

Am 8. Juli 2016 um 13:44:45, Tino Heth (2th@gmx.de) schrieb:

There are (were?) plans for generalized property behaviors; those would be used to implement lazy, as well as didSet/willSet, and could incorporate many other things (including injection)

Of course, an option to observe variables would be handy — but there's always a price to pay, and you'll at least need a way to opt-out: Even if you actually don't observe a property that changes hundreds of times per second, the hooks alone could degrade performance (it's another question if it's wise to have such properties :wink:

Tino


(Chris Lattner) #7

Indeed, the latest draft is here:

This will surely come back sometime after Swift 3.0.

-Chris

···

On Jul 8, 2016, at 4:43 AM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

There are (were?) plans for generalized property behaviors; those would be used to implement lazy, as well as didSet/willSet, and could incorporate many other things (including injection)


(David Sweeris) #8

I think I’d say that your “local” willset should be called before the module’s, and your local didset should be called after the module’s. This ensures that module’s code executes closest to when the memory gets changed.

- Dave Sweeris

···

On Jul 8, 2016, at 6:45 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

It’s clear that we should decide on when our observer will be executed. In the example from above I pretended that my observer will be executed after the observer from the module itself.

When we set a.member2 the observer for member1 on our side will be called first, follows by member2 observer, which ‘might’ not be what we need.

I’d suggest that if this ‘feature’ might ever be considered for Swift that we should be able to set the execution order.

Bikeshedding:

observe(first) // called before observer from the module are called
observe(last) // called after the observer from the module where called