Order of QML property's dependency evaluation
-
I have a CustomQMLComponent. It has 3 properties. p3 is dependent on p1 & p2. p1 & p2 are set when an instance of CustomQMLComponent is created.
Questions:
- By the time p3 is evaluated, will p1 & p2 always have the values set by the caller.
- What is the recommended way to set p3, as shown below or as in the commented statement?
CustomQMLComponent.qml:
Item { required property string p1 property bool p2 : false property int p3: cppContextPropertyObj.slot(p1, p2) //Component.onCompleted: p3 = cppContextPropertyObj.slot(p1, p2) }
main.qml:
CustomQMLComponent{ p1: "my_string" p2: true }
-
In QML there is no order of evaluation. The language is declarative, meaning: when
p1
changes, all other properties depending on it will change, too. Whenp2
changes, all other properties depending on it will change.So in you example,
p3
will be calculated at least twice initially. QML engine does go through properties in the order of their creation, but that is an implementation detail, you should never depend on it.To answer your second question: if you want
p3
to update dynamically based on changes ofp1
andp2
, you have to use a binding (as you have it now). If you want to set it only once and not update later, use the solution you have commented out. -
p1 and p2 have static value assignments, whereas p3 has a binding value assignment.
As per this old article: https://www.kdab.com/qml-engine-internals-part-2-bindings/, static value assignments happen during creation phase and binding value assignments happen at the end of creation phase.
Case 1:
CustomQMLComponent{}
In this case, based on the above article, p1 & p2 values are set by the time p3 value is set.
Case 2:
CustomQMLComponent{ p1: "my_string" p2: true }
What happens in this case?
In a more general sense, what happens when properties of a component are set when creating an instance of the component? Are the properties initialized with default values and then overridden by the new instance's values? Or, the properties are initialized just once with the default/new values.
-
I don't know, but you can easily check this: just add some logs:
Item { required property string p1 property bool p2 : false property int p3: cppContextPropertyObj.slot(p1, p2) //Component.onCompleted: p3 = cppContextPropertyObj.slot(p1, p2) onP1Changed: console.log("P1 changed to:", p1) onP2Changed: console.log("P2 changed to:", p2) onP3Changed: console.log("P3 changed to:", p3) }
As I mentioned though, in practice it does not matter what exactly happens.
-
@b-arun-kumar said in Order of QML property's dependency evaluation:
Response from Qt Support:As per this old article: https://www.kdab.com/qml-engine-internals-part-2-bindings/, static value assignments happen during creation phase and binding value assignments happen at the end of creation phase.
That is how it should be, literals first, then functions. But it is not actually documented so in theory it could change. This is also only true for simple literal assignments. Anything even slightly hinting about complexity makes QML engine postpone them together with all those needing the evaluation. For example it happens if you wrap the value with {} like this: p2: {true}
Case 1:
CustomQMLComponent{}
In this case, based on the above article, p1 & p2 values are set by the time p3 value is set.
The order in which these "static" properties are set is undefined and also the order in which more complex expressions are done are undefined. So it is best to avoid making assumptions about the order.
Case 2:
CustomQMLComponent{ p1: "my_string" p2: true }
What happens in this case?
In a more general sense, what happens when properties of a component are set when creating an instance of the component? Are the properties initialized with default values and then overridden by the new instance's values? Or, the properties are initialized just once with the default/new values.
Just once. Although the properties do of course have some default value before the value in QML is assigned. The initial value set in constructor of a C++ class, or in case of QML defined property, default constructed value of the type (empty string, 0, false or null in case it is QObject* type).
And why this could be important is because something like onXXXChanged signals are handled immediately when they occur and thus it could be ran before all those "static" assignment are done. Consider for example:
onP1Changed: if (p2) {...} else {...}
QML engine does not know that there is some dependency to p2 on p1 value change and in case p1 gets assigned before p2, this could take unexpected path and if p2 value change is not explicitly also handled properly in this case, could lead to mismatched state.