glibvalagobjectreference-cycle

Vala closure reference cycle


I'm writing a class in Vala where I bind two of the same object's properties together, with a closure to transform one to the other.

class Foo : Object
{
    public int num { get; set; }
    public int scale = 2;
    public int result { get; set; }

    construct {
        this.bind_property("num", this, "result", 0,
            (binding, src, ref dst) => {
                var a = src.get_int();
                var b = this.scale;
                var c = a * b;
                dst.set_int(c);
            }
        );
    }
}

The closure keeps a reference this (because I use this.scale), which creates a reference cycle which is keeping my class alive even when all other references to it are lost.

The binding will only be removed when the reference count reaches 0, but refcount will only reach 0 when the biding and its closure is removed.

Is there a way to make the closure's reference to this weak? Or to probe when the refcount reaches 1 in order to remove it?


Solution

  • This is a known defficiency of the Vala compiler and is discussed in this issue.

    For now, the problem can be avoided by doing the binding from a static method where the closure does not capture this.

    class Foo : Object
    {
        public int num { get; set; }
        public int scale = 2;
        public int result { get; set; }
    
        construct {
            this.bind_properties(this);
        }
    
        private static void bind_properties(Foo this_)
        {
            weak Foo weak_this = this_;
    
            this_.bind_property("num", this_, "result", 0,
                (binding, src, ref dst) => {
                    var a = src.get_int();
                    var b = weak_this.scale;
                    var c = a * b;
                    dst.set_int(c);
                }
            );
        }
    }