strange property observer behavior


(Adel Zhang) #1

Hi all

It sounds convenient to monitor change in property's value using property observer.
But TSPL(The Swift Programming Language) talk little about property observer. There
are some questions abouts property observer.

1) when `didSet` observer will call?

I assume it's fine that changing property's value in `didSet` observer.

     class Foo {
         var a: Int = 0 {
             didSet {
                 print("didset")
                 a = a + 1
             }
         }
     }

     let foo = Foo()
     foo.a = 4 // only output "didset" once

Why it don't cause infinite loop?

2) infinite loop

     // this code snippet cause inifinite loop
     class Foo {
         var a: Int = 0 {
             didSet {
                 b = a + 1
             }
         }

         var b: Int = 1 {
             didSet {
                 a = b - 1
             }
         }
     }

     let foo = Foo()
     foo.a = 2

3) override property observer

     class Base {
         var a: Int = 0 {
             didSet {
                 print("base didset")
             }
         }
     }

     class Child : Base {
         override var a : Int {
             didSet {
                 print("child didset")
             }
         }
     }

     let child = Child()
     child.a = 2 // output "base didset" and "child didset"
     let base = child as Base
     base.a = 4 // still output "base didset" and "child didset"

Why overriding property observer still call parent's `didSet` observer?

···

--
Adel


(Zhao Xin) #2

1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some beginner's
flaw.

​2) infinite loop

​If you intended to do things bad, things ​went bad.

3) override property observer

​You mentioned "TSPL(The Swift Programming Language) ​", and it says in it:

“NOTE

The willSet and didSet observers of superclass properties are called when a
property is set in a subclass initializer, after the superclass initializer
has been called. They are not called while a class is setting its own
properties, before the superclass initializer has been called.

For more information about initializer delegation, see Initializer
Delegation for Value Types and Initializer Delegation for Class Types.”

https://itun.es/us/k5SW7.l

You didn't provide a `init()`, but since you properties were already set.
There was a hidden `init()` when you called `Child()`.

Last,

let base = child as Base
base.a = 4 // still output "base didset" and "child didset"

In Swift, as or as! won't change the instance's dynamic type. So it does
nothing. `type(of:base)` is still `Child`.

Zhaoxin

···

From: Apple Inc. “The Swift Programming Language (Swift 3 Beta)”。 iBooks.

On Sun, Sep 4, 2016 at 6:25 PM, adelzhang via swift-users < swift-users@swift.org> wrote:

Hi all

It sounds convenient to monitor change in property's value using property
observer.
But TSPL(The Swift Programming Language) talk little about property
observer. There
are some questions abouts property observer.

1) when `didSet` observer will call?

I assume it's fine that changing property's value in `didSet` observer.

    class Foo {
        var a: Int = 0 {
            didSet {
                print("didset")
                a = a + 1
            }
        }
    }

    let foo = Foo()
    foo.a = 4 // only output "didset" once

Why it don't cause infinite loop?

2) infinite loop

    // this code snippet cause inifinite loop
    class Foo {
        var a: Int = 0 {
            didSet {
                b = a + 1
            }
        }

        var b: Int = 1 {
            didSet {
                a = b - 1
            }
        }
    }

    let foo = Foo()
    foo.a = 2

3) override property observer

    class Base {
        var a: Int = 0 {
            didSet {
                print("base didset")
            }
        }
    }

    class Child : Base {
        override var a : Int {
            didSet {
                print("child didset")
            }
        }
    }

    let child = Child()
    child.a = 2 // output "base didset" and "child didset"
    let base = child as Base
    base.a = 4 // still output "base didset" and "child didset"

Why overriding property observer still call parent's `didSet` observer?

--
Adel

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


(Zhao Xin) #3

1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some beginner's

flaw.

Above is incorrect. You can change property's value in `didSet`, that won't
cause didSet called again as it is intended to give you the opportunity to
do that.

​2) infinite loop

This can't apply the above rule as they set each other, causing the
infinite loops.

Zhaoxin

···

On Sun, Sep 4, 2016 at 7:41 PM, Zhao Xin <owenzx@gmail.com> wrote:

1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some beginner's
flaw.

​2) infinite loop

​If you intended to do things bad, things ​went bad.

3) override property observer

​You mentioned "TSPL(The Swift Programming Language) ​", and it says in it:

“NOTE

The willSet and didSet observers of superclass properties are called when
a property is set in a subclass initializer, after the superclass
initializer has been called. They are not called while a class is setting
its own properties, before the superclass initializer has been called.

For more information about initializer delegation, see Initializer
Delegation for Value Types and Initializer Delegation for Class Types.”

From: Apple Inc. “The Swift Programming Language (Swift 3 Beta)”。 iBooks.
https://itun.es/us/k5SW7.l

You didn't provide a `init()`, but since you properties were already set.
There was a hidden `init()` when you called `Child()`.

Last,

let base = child as Base
base.a = 4 // still output "base didset" and "child didset"

In Swift, as or as! won't change the instance's dynamic type. So it does
nothing. `type(of:base)` is still `Child`.

Zhaoxin

On Sun, Sep 4, 2016 at 6:25 PM, adelzhang via swift-users < > swift-users@swift.org> wrote:

Hi all

It sounds convenient to monitor change in property's value using property
observer.
But TSPL(The Swift Programming Language) talk little about property
observer. There
are some questions abouts property observer.

1) when `didSet` observer will call?

I assume it's fine that changing property's value in `didSet` observer.

    class Foo {
        var a: Int = 0 {
            didSet {
                print("didset")
                a = a + 1
            }
        }
    }

    let foo = Foo()
    foo.a = 4 // only output "didset" once

Why it don't cause infinite loop?

2) infinite loop

    // this code snippet cause inifinite loop
    class Foo {
        var a: Int = 0 {
            didSet {
                b = a + 1
            }
        }

        var b: Int = 1 {
            didSet {
                a = b - 1
            }
        }
    }

    let foo = Foo()
    foo.a = 2

3) override property observer

    class Base {
        var a: Int = 0 {
            didSet {
                print("base didset")
            }
        }
    }

    class Child : Base {
        override var a : Int {
            didSet {
                print("child didset")
            }
        }
    }

    let child = Child()
    child.a = 2 // output "base didset" and "child didset"
    let base = child as Base
    base.a = 4 // still output "base didset" and "child didset"

Why overriding property observer still call parent's `didSet` observer?

--
Adel

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


(Adel Zhang) #4

Thanks for reply.

How does Swift choose *rules* as you said?

Swfit encourage to override the property observer. But when we change the own property in Child class's `didSet` observer, that would cause infinite loop:

     class Base {
         var a: Int = 0
     }

     class Child : Base {
         override var a: Int {
             didSet {
                  a = a + 1
             }
         }
      }

      let child = Child()
      child.a = 3

Any differcen with situation 1?

···

在 Sun, 04 Sep 2016 20:12:42 +0800,Zhao Xin <owenzx@gmail.com> 写道:

1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some beginner's flaw.

Above is incorrect. You can change property's value in `didSet`, that won't cause didSet called again as it is intended to give you the opportunity to do that.

​2) infinite loop

This can't apply the above rule as they set each other, causing the infinite loops.
Zhaoxin

On Sun, Sep 4, 2016 at 7:41 PM, Zhao Xin <owenzx@gmail.com> wrote:

1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some beginner's flaw.

​2) infinite loop

​If you intended to do things bad, things ​went bad.

3) override property observer

​You mentioned "TSPL(The Swift Programming Language) ​", and it says in it:

“NOTE

The willSet and didSet observers of superclass properties are called when a property is set in a subclass initializer, after the superclass initializer has been called. They >are not called while a class is setting its own properties, before the superclass initializer has been called.

For more information about initializer delegation, see Initializer Delegation for Value Types and Initializer Delegation for Class Types.”

From: Apple Inc. “The Swift Programming Language (Swift 3 Beta)”。 iBooks. https://itun.es/us/k5SW7.l

You didn't provide a `init()`, but since you properties were already set. There was a hidden `init()` when you called `Child()`.

Last,

let base = child as Base

base.a = 4 // still output "base didset" and "child didset"

In Swift, as or as! won't change the instance's dynamic type. So it does nothing. `type(of:base)` is still `Child`.

Zhaoxin

On Sun, Sep 4, 2016 at 6:25 PM, adelzhang via swift-users > <swift-users@swift.org> wrote:

Hi all

It sounds convenient to monitor change in property's value using property observer.
But TSPL(The Swift Programming Language) talk little about property observer. There
are some questions abouts property observer.

1) when `didSet` observer will call?

I assume it's fine that changing property's value in `didSet` observer.

   class Foo {
       var a: Int = 0 {
           didSet {
               print("didset")
               a = a + 1
           }
       }
   }

   let foo = Foo()
   foo.a = 4 // only output "didset" once

Why it don't cause infinite loop?

2) infinite loop

   // this code snippet cause inifinite loop
   class Foo {
       var a: Int = 0 {
           didSet {
               b = a + 1
           }
       }

       var b: Int = 1 {
           didSet {
               a = b - 1
           }
       }
   }

   let foo = Foo()
   foo.a = 2

3) override property observer

   class Base {
       var a: Int = 0 {
           didSet {
               print("base didset")
           }
       }
   }

   class Child : Base {
       override var a : Int {
           didSet {
               print("child didset")
           }
       }
   }

   let child = Child()
   child.a = 2 // output "base didset" and "child didset"
   let base = child as Base
   base.a = 4 // still output "base didset" and "child didset"

Why overriding property observer still call parent's `didSet` observer?

--
Adel

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


(Jens Alfke) #5

I’m not a Swift guru, but that seems like a bug to me. The book explicitly says that it’s legal for a didSet block to set the property value, with no caveats about overridden properties.

You should be able to work around this by having the subclass override the `set` block instead, and pass the modified value to the superclass. (It’s probably slightly more efficient too.)

—Jens

···

On Sep 4, 2016, at 8:11 AM, adelzhang via swift-users <swift-users@swift.org> wrote:

Swfit encourage to override the property observer. But when we change the own property in Child class's `didSet` observer, that would cause infinite loop:


(Gerard Iglesias) #6

Hi,

didSet is called as soon as the property is stored… Excepted when the value is stored in the initialiser code.

For me it is completely predictable that your code enter an infinite loop

Regards

···

On 4 Sep 2016, at 17:11, adelzhang via swift-users <swift-users@swift.org> wrote:

Thanks for reply.

How does Swift choose *rules* as you said?

Swfit encourage to override the property observer. But when we change the own property in Child class's `didSet` observer, that would cause infinite loop:

    class Base {
        var a: Int = 0
    }

    class Child : Base {
        override var a: Int {
            didSet {
                 a = a + 1
            }
        }
     }
    
     let child = Child()
     child.a = 3

Any differcen with situation 1?

在 Sun, 04 Sep 2016 20:12:42 +0800,Zhao Xin <owenzx@gmail.com> 写道:

1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some beginner's flaw.

Above is incorrect. You can change property's value in `didSet`, that won't cause didSet called again as it is intended to give you the opportunity to do that.

​2) infinite loop

This can't apply the above rule as they set each other, causing the infinite loops.

Zhaoxin

On Sun, Sep 4, 2016 at 7:41 PM, Zhao Xin <owenzx@gmail.com <mailto:owenzx@gmail.com>> wrote:
1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some beginner's flaw.

​2) infinite loop

​If you intended to do things bad, things ​went bad.

3) override property observer

​You mentioned "TSPL(The Swift Programming Language) ​", and it says in it:

“NOTE

The willSet and didSet observers of superclass properties are called when a property is set in a subclass initializer, after the superclass initializer has been called. They are not called while a class is setting its own properties, before the superclass initializer has been called.

For more information about initializer delegation, see Initializer Delegation for Value Types and Initializer Delegation for Class Types.”

From: Apple Inc. “The Swift Programming Language (Swift 3 Beta)”。 iBooks. https://itun.es/us/k5SW7.l

You didn't provide a `init()`, but since you properties were already set. There was a hidden `init()` when you called `Child()`.

Last,

let base = child as Base
base.a = 4 // still output "base didset" and "child didset"

In Swift, as or as! won't change the instance's dynamic type. So it does nothing. `type(of:base)` is still `Child`.

Zhaoxin

On Sun, Sep 4, 2016 at 6:25 PM, adelzhang via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi all

It sounds convenient to monitor change in property's value using property observer.
But TSPL(The Swift Programming Language) talk little about property observer. There
are some questions abouts property observer.

1) when `didSet` observer will call?

I assume it's fine that changing property's value in `didSet` observer.

    class Foo {
        var a: Int = 0 {
            didSet {
                print("didset")
                a = a + 1
            }
        }
    }

    let foo = Foo()
    foo.a = 4 // only output "didset" once

Why it don't cause infinite loop?

2) infinite loop

    // this code snippet cause inifinite loop
    class Foo {
        var a: Int = 0 {
            didSet {
                b = a + 1
            }
        }

        var b: Int = 1 {
            didSet {
                a = b - 1
            }
        }
    }

    let foo = Foo()
    foo.a = 2

3) override property observer

    class Base {
        var a: Int = 0 {
            didSet {
                print("base didset")
            }
        }
    }

    class Child : Base {
        override var a : Int {
            didSet {
                print("child didset")
            }
        }
    }

    let child = Child()
    child.a = 2 // output "base didset" and "child didset"
    let base = child as Base
    base.a = 4 // still output "base didset" and "child didset"

Why overriding property observer still call parent's `didSet` observer?

--
Adel

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

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


(Zhao Xin) #7

It seems like a bug. You should file it.

Zhaoxin

···

On Sun, Sep 4, 2016 at 11:11 PM, <adelzhang@qq.com> wrote:

Thanks for reply.

How does Swift choose *rules* as you said?

Swfit encourage to override the property observer. But when we change the
own property in Child class's `didSet` observer, that would cause infinite
loop:

    class Base {
        var a: Int = 0
    }

    class Child : Base {
        override var a: Int {
            didSet {
                 a = a + 1
            }
        }
     }

     let child = Child()
     child.a = 3

Any differcen with situation 1?

在 Sun, 04 Sep 2016 20:12:42 +0800,Zhao Xin <owenzx@gmail.com> 写道:

1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some beginner's

flaw.

Above is incorrect. You can change property's value in `didSet`, that
won't cause didSet called again as it is intended to give you the
opportunity to do that.

​2) infinite loop

This can't apply the above rule as they set each other, causing the
infinite loops.

Zhaoxin

On Sun, Sep 4, 2016 at 7:41 PM, Zhao Xin <owenzx@gmail.com> wrote:

1) when `didSet` observer will call?

​For me, it is more like Swift developer tries to override some
beginner's flaw.

​2) infinite loop

​If you intended to do things bad, things ​went bad.

3) override property observer

​You mentioned "TSPL(The Swift Programming Language) ​", and it says in
it:

“NOTE

The willSet and didSet observers of superclass properties are called when
a property is set in a subclass initializer, after the superclass
initializer has been called. They are not called while a class is setting
its own properties, before the superclass initializer has been called.

For more information about initializer delegation, see Initializer
Delegation for Value Types and Initializer Delegation for Class Types.”

From: Apple Inc. “The Swift Programming Language (Swift 3 Beta)”。 iBooks.
https://itun.es/us/k5SW7.l

You didn't provide a `init()`, but since you properties were already set.
There was a hidden `init()` when you called `Child()`.

Last,

let base = child as Base
base.a = 4 // still output "base didset" and "child didset"

In Swift, as or as! won't change the instance's dynamic type. So it does
nothing. `type(of:base)` is still `Child`.

Zhaoxin

On Sun, Sep 4, 2016 at 6:25 PM, adelzhang via swift-users < >> swift-users@swift.org> wrote:

Hi all

It sounds convenient to monitor change in property's value using
property observer.
But TSPL(The Swift Programming Language) talk little about property
observer. There
are some questions abouts property observer.

1) when `didSet` observer will call?

I assume it's fine that changing property's value in `didSet` observer.

    class Foo {
        var a: Int = 0 {
            didSet {
                print("didset")
                a = a + 1
            }
        }
    }

    let foo = Foo()
    foo.a = 4 // only output "didset" once

Why it don't cause infinite loop?

2) infinite loop

    // this code snippet cause inifinite loop
    class Foo {
        var a: Int = 0 {
            didSet {
                b = a + 1
            }
        }

        var b: Int = 1 {
            didSet {
                a = b - 1
            }
        }
    }

    let foo = Foo()
    foo.a = 2

3) override property observer

    class Base {
        var a: Int = 0 {
            didSet {
                print("base didset")
            }
        }
    }

    class Child : Base {
        override var a : Int {
            didSet {
                print("child didset")
            }
        }
    }

    let child = Child()
    child.a = 2 // output "base didset" and "child didset"
    let base = child as Base
    base.a = 4 // still output "base didset" and "child didset"

Why overriding property observer still call parent's `didSet` observer?

--
Adel

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


(Adel Zhang) #8

Hi,

The following code works fine. The property `a` is stored twice. But
it don't enter infinite loop.

     class Foo {
         var a: Int = 0 {
              didSet {
                  a = a + 1
              }
         }
     }

     let foo = Foo()
     foo.a = 2
     print(foo.a) // output 3

Regards

--adel

···

在 Mon, 05 Sep 2016 00:27:16 +0800,Gerard Iglesias <gerard_iglesias@me.com> 写道:

Hi,

didSet is called as soon as the property is stored… Excepted when the value is stored in the initialiser code.

For me it is completely predictable that your code enter an infinite loop

Regards

On 4 Sep 2016, at 17:11, adelzhang via swift-users >> <swift-users@swift.org> wrote:

Thanks for reply.

How does Swift choose *rules* as you said?

Swfit encourage to override the property observer. But when we change the own property in Child class's `didSet` observer, that would cause infinite loop:

    class Base {
        var a: Int = 0
    }

    class Child : Base {
        override var a: Int {
            didSet {
                 a = a + 1
            }
        }
     }

     let child = Child()
     child.a = 3

Any differcen with situation 1?