[Development] The future of QProperty and QBindable

Ulf Hermann ulf.hermann at qt.io
Fri Mar 7 10:14:56 CET 2025


Hi,

We've had a discussion [1] about QProperty and QBindable during the last 
contributors' summit, but unfortunately didn't reach any conclusion. 
I'll summarize the most important part of the discussion here:

"There is functionality to retrofit Q_PROPERTY with synthetic bindables."

This may be surprising but bear with me. First, (belated) big thanks to 
Patrick Stewart for making this happen. The relevant API are the 
constructors for QBindable [2][3].


Without integration with moc, Q_PROPERTY and QML, QProperty and 
QBindable would be fairly simple and self-contained pieces of code. They 
could be moved to a separate library, e.g. QtBindable and live there 
without hurting anyone.

Conversely, the deep integration with moc, Q_PROPERTY and QML gives us a 
lot of headaches. If you use a QProperty to back a Q_PROPERTY you need 
to be extremely careful when writing getters and setter, so that you 
don't accidentally produce spurious dependencies. A classic example is a 
setter first comparing the value before setting it. You can't just do 
"if (someQProperty.value() == newValue)". You have to do 
"someProperty.valueBypassingBindings()". Furthermore, you need to call 
removeBindingUnlessInWrapper() at the right place so that any bindings 
to the property are broken when setting a new value (even if the value 
is the same). The complexity grows if you have properties that depend on 
each other or otherwise interact. In general, this is not something we 
can ask users to get right. We ourselves have produced a lot of bugs 
[4][5] when introducing bindables into the few places in Qt where we 
have them now. And we're not done fixing them [6]. Finally, the 
QBindingStorage member in QObjectData that makes all this possible, 
increases the size of every QObject by two pointers, no matter if it 
uses bindables or not.


Let's take a step back here, though. The original idea of introducing 
QProperty and QBindable was twofold:

1. Offer a convenient C++ API for bindings.
2. Enable the Qt Quick Compiler to generate better C++ code for bindings.

1 can be achieved without deep integration into moc and Q_PROPERTY. An 
external adapter for Q_PROPERTY is generally enough to connect 
Q_PROPERTY with bindables. Granted, the result will probably be slower 
than a deeply integrated bindable, However, given the amount of 
optimization we needed to put in to get any visible performance edge for 
QProperty/QBindable over classic signal/slot connections at all, I 
expect the difference to be small.

2 turned out to be chimera. qmlsc can generate rather performant code 
for a binding using QProperty directly, but there are preconditions:
a, The binding needs to be compilable in the first place.
b, You need to use direct mode [7], which implies private API and 
accessible headers.
c, The property written to has to be bindable.
d, The properties read from have to be bindable.
In practice, this rarely materializes. On the flip side, when not used 
directly like this, but rather through dynamically typed lookups inside 
QQmlEngine, or in the adaptor methods for AOT-compiled non-direct code, 
QProperty and QBindable do not offer a clear performance benefit over 
regular READ/WRITE/NOTIFY properties. They do, however, produce a lot of 
complexity. I'm currently working on the property-to-property binding we 
use to implement the interaction between models and delegates via 
required properties [8]. This thing requires four different 
implementations to cover all the permutations. And this is just one example.


So here is my suggestion:

1, Deprecate the BINDABLE attribute to Q_PROPERTY. We probably can't 
have moc produce a warning about it right away, but we can already adapt 
the documentation.
2, Deprecate QObjectBindableProperty and friends.
3, Revert our own bindable Q_PROPERTYs to be backed by simple data 
members rather than QProperty again. Implement the public fooBindable() 
methods in terms of the Q_PROPERTY adaptors for QBindable and deprecate 
them. Drop all the BINDABLEs in private API.
4, Remove the integration with QProperty and QBindable in QML. QML will 
always use the READ/WRITE/NOTIFY methods again and ignore any BINDABLE.
5, In Qt7, move the remaining QProperty and QBindable code into a 
separate library.

This sounds easy, but there is a slight caveat: You can omit the change 
signal if you have a BINDABLE, and QML will currently still be able to 
listen to the property. I guess some projects are doing this. If QML 
were to completely ignore all bindables, it would not be able to get 
notified about those properties anymore. Therefore, both moc and the QML 
engine should warn about BINDABLEs without NOTIFY. Ideally, as a porting 
helper, moc could temporarily accept "NOTIFY default" to generate a 
notification signal from a bindable, but I don't know if we can pull 
this off. Only afterwards, maybe after two minor versions of Qt, we can 
remove bindable support from QML.


I'm registering another session for the upcoming contributors' summit in 
May [9], but I would appreciate opinions already before.

best regards,
Ulf

[1] https://wiki.qt.io/QtCS2024_QProperty
[2] https://doc.qt.io/qt-6/qbindable.html#QBindable
[3] https://doc.qt.io/qt-6/qbindable.html#QBindable-1
[4] https://bugreports.qt.io/browse/QTBUG-116211
[5] https://bugreports.qt.io/browse/QTBUG-116345 and its sub-tasks
[6] https://codereview.qt-project.org/c/qt/qtbase/+/611485
[7] https://doc.qt.io/Qt-6/qtqml-qml-script-compiler.html#direct-mode
[8] 
https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/qml/qml/qqmlpropertytopropertybinding.cpp
[9] https://wiki.qt.io/Qt_Contributor_Summit_2025_-_Program


More information about the Development mailing list