[Development] On QML, ownership, QObject-trees and QSharedPointer

christopher.adams at nokia.com christopher.adams at nokia.com
Fri May 25 02:35:23 CEST 2012


> > In QtQuick 2.0 (ie, Qt 5.0), we are thinking about using property var
> > more often in the implementation (eg, of qobject-derived-type
> > properties) to avoid some of those edge-cases, and providing more
> > consistent (and useful) referencing semantics.
> Can you say what 'var' is and why it would help?

In QtQuick 1.x, you could not define a "JavaScript var-type property" in a QML item.  The closest thing provided was "property variant" which, internally, is a QVariant.  Assigning a JavaScript object to that property would result in it being converted to a QVariantMap.  Accessing that property from JS would result in that QVariantMap being converted back into a JS object.  You could not store a JS function reference, or any other "special" JS value in a "property variant" property (eg, null, undefined).

In QtQuick 2.0, we deprecated "property variant" and added "property var".  Internally, "property var" properties are JS values.  Thus, you can store anything created in JS, including JS function references.  This allows greater dynamicity and flexibility.  Only when you access that property from C++ (via QObject::property() or QQmlProperty::read()) will it be converted to a QVariant (following the same conversion rules as for any other JS value to QVariant conversion).

If we were to implement "property variant" as a synonym for "property var" in QtQuick 2.0, the code base would be simplified, and the referencing semantics made more consistent (more on this later).  I haven't benchmarked the performance impact of such a change, yet, however.

> Does what you say about handling qobject-derived-type properties have
> anything to do with this:
> https://codereview.qt-project.org/#change,13006
> https://codereview.qt-project.org/#change,13007
> or do you have something else in mind?

When I said "qobject-derived-type" I should have said "User-defined (via custom components) QML types".
Eg, if you have a file named MyButton.qml, you can use MyButton as a type.  It is a QQuickItem-derived type (and thus a QObject-derived type).

The problem is that currently, the ownership semantics are (in my opinion) quite strange.  In particular:

import QtQuick 2.0
Item {
    id: root
    property MyButton buttonOne: MyButton { ... }
    property MyButton buttonTwo
    property variant buttonThree: MyButton { ... }
    property variant buttonFour
    property var buttonFive: MyButton { ... }
    property var buttonSix

    function generateButton() {
        var c = Qt.createComponent("MyButton.qml");
        var o = c.createObject(null); // no explicit parent
        return o;

    function generateButtons() {
        buttonTwo = generateButton();
        buttonFour = generateButton();
        buttonSix = generateButton();

    Component.onCompleted: {
        gc(); gc(); gc(); gc();

That example will cause button two and four to be collected / destroyed via garbage collection.
Because the generated buttons had no explicit parent given, they have JS ownership and will be collected if no JS references to them exist.
QVariant-backed property types (like MyButton and variant) don't store JS values (and thus don't cause JS references to exist) and thus buttons two and four will be collected.

The only reason why buttonOne and buttonThree aren't collected is that we explicitly set the parent of the RHS item, during instantiation (in the VME, during CreateSimpleObject).  To me, it seems strange that root is the parent of buttonOne and buttonThree, but not the parent of buttonTwo or buttonFour (given that the only real difference is declaration vs assignment), and it is certainly strange that even though buttonTwo and buttonFour "reference" their associated values, the gc will still collect them.

Note that buttons five and six are not collected, because they are JS values (which will prevent the gc from collecting what they reference).

See QTBUG-24767 for more information.  There is a change which fixes the referencing strangeness, but it may have a performance impact during gc cycles, which we are currently evaluating.


More information about the Development mailing list