On Wed, 26 Aug 2020 at 09:20, Lars Knoll <[email protected]> wrote: > > Hi all, > > After the long discussions a few weeks back about the new property system and > some trial to port the existing properties over to the new system, it became > somewhat clear to me that the approach we had tried so far won’t work and be > ready in time for the feature freeze. > > The main problems identified where > * the reliance on [[no_unique_address]] which is a C++20 feature > * The additional storage overhead for bindings > * the fact that the decision whether a property can use bindings or not is a > decision that changes the ABI. This implied, that we could not add binding > support to a property without breaking binary compatibility after 6.0 has > been released. > > So I sat down and did quite a bit of work redesigning the system over the > last three weeks. I am pretty happy with the result I now came up with, and > hope to have it all merged before the feature freeze. > > The redesigned system keeps most of the low level API the same, so you still > have QProperty<T> and QPropertyBinding to create bindings. But it does > integrate much better with the existing property system that we have from Qt > 5.x. > > QProperty<T> has as a design choice coupled the storage of the property data > with an additional pointer to store any possible binding related data. The > redesign breaks this hard dependency, and allows separating the data storage > from the binding data. > > I’ve added a new QBindingStorage class that can store bindings for a whole > object. QObject now has one of those by default. If bindings aren’t used this > comes down to two additional pointers inside QObjectPrivate (and not one > additional pointer per property). The class is currently marked internal, but > can in principle be used to add a binding storage also to other types of > objects. > > Together with QBindingStorage, we now have a couple of new classes to store > properties without memory overhead. As QBindingStorage and those classes are > aimed at QObject derived classes (others should use QProperty<T> with inline > binding storage), those classes are called > QObjectBindable/Computed/CompatProperty. They all add binding support to a > property, but serve slightly different purposes: > * QObjectBindableProperty should be the default to use, especially for new > code. It does lazy binding evaluation, and does support an optional changed > signal. > * QObjectComputedProperty can be used for read-only properties where the > value is computed on the fly. It supports being used in binding expressions, > but you can not create a binding on it (as it’s read-only). > * QObjectCompatProperty is there to help port existing properties over and > make them bindable. It does eager binding evaluation and calls the existing > property setter. This is the class to use for easy porting if you can’t or > don’t want to refactor a lot of code. It needs to evaluate bindings eagerly, > as many of the existing property setters have side effects. > > Using those classes happens through a > Q_OBJECT_BINDABLE/COMPUTED/COMPAT_PROPERTY macro. We need the macro to be > able to get back from the properties to the binding storage. This is the one > place where we rely on a non standard (but supported by all our compilers) > feature. Namely the ability to call offsetof() on non-standard types. > > Binding support through the public API is now exposed through a QBindable<T> > class, that provides the binding interface towards those properties. In > addition to the getter and setter, the object will also need one > Bindable<Type> bindableProp() for a property prop to make the binding support > accessible. This method will need to get implemented by the developer. > > As a final piece, moc can also generate some support for introspecting those > bindings. This simply requires adding a “BINDABLE bindableProp” section to > the existing Q_PROPERTY() macro. With that, you can set and inspect bindings > though QMetaProperty. > > You can find an example where I ported QAbstractAnimation to enable bindings > here: https://codereview.qt-project.org/c/qt/qtbase/+/310748. > > As you can see, it only required changing the storage of the property data to > use Q_OBJECT_BINDABLE(COMPUTED)_PROPERTY, adding the bindingProp() accessors > to the public API and making them known to the meta object system by adding > the BINDABLE section to Q_PROPERTY(). > > To summarise the advantages of the redesigned system: > > * Very little memory overhead if bindings aren’t used > * Very low runtime overhead if bindings aren’t used > * Binding support can be added to properties in QObjects in a binary > compatible way > * Straight forward extension of the existing and known property system > * Much easier to port existing properties
I think this is a very good solution and quite a nice API. Simon _______________________________________________ Development mailing list [email protected] https://lists.qt-project.org/listinfo/development
