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

Reply via email to