[Development] Property bindings in Qt 6

Simon Hausmann Simon.Hausmann at qt.io
Tue Oct 1 15:32:06 CEST 2019


Am 01.10.19 um 15:18 schrieb Eike Ziller:
>
>> On 26. Sep 2019, at 17:02, Simon Hausmann <Simon.Hausmann at qt.io> wrote:
>>
>> Hi,
>>
>> Earlier this year, Olivier, Samuel, Auri and I worked on a project to re-evaluate how we could bring the declarative Qt Quick approach of doing user interfaces closer to C++, in order to allow building and running user interfaces in very memory and processor-power constrained environments. There were many different outcomes of this. One of them was that we figured out a way to compile QML binding expressions down to full C++, without any run-time interpretation. This required building a new way of defining properties and their relationships, a new property binding system. The results were so convincing that the plan was born to productize this for Qt 6 in multiple layers and steps. I'd like to initiate a first step in that direction by proposing API and functionality for Qt 6 and briefly outline how we see the building blocks apply to QML and Qt Quick:
>>
>> In QML, today, properties consist of a type, a setter function and a getter function, and the functions are implemented by the developer. There is also a change signal that needs to be emitted when the value changes.
>>
>> Binding expressions declared in .qml files are created behind the scenes and the QML engine makes sure to call the getter functions during the evaluation and the setter function to write the result. Through a connection to the change signal, bindings are automatically re-evaluated when properties change and the new values are passed to the setter functions. It's pretty magic and it works, but it requires a fair amount of indirection and side-loading of data structures.
>>
>> I would like to propose an API that replaces the setter and getter functions on objects with a new property template class that encapsulates the property value instead, and the ability to tie binding expressions to these properties for automatic updates. In short, it looks like this:
>>
> Hi,
>
>>      QProperty<QString> surname("John");
>>      QProperty<QString> lastname("Smith");
>>
>>      QProperty<QString> fullname;
>>      fullname.setBinding([&]() { return surname() + " " + lastname(); });
>>
>>      qDebug() << fullname(); // Prints "John Smith"
>>
>>      surname = "Emma"; // Marks binding expression as dirty
>>
>>      qDebug() << fullname(); // Re-evaluates the binding expression and prints "Emma Smith"
>>
>>
>> You can see a work-in-progress patch for this in Gerrit at
>>
>>      https://codereview.qt-project.org/c/qt/qtbase/+/275352
>>
> I’m all for a more declarative coding style also in C++.
> I’m wondering if we are re-inventing part of Reactive Programing a la ReactiveX with QProperty, though?


I suppose we are. It's not black or white I think :)


> The above looks similar to (sodium-cxx):
>
>      cell_sink<QString> surname("John");
>      cell_sink<QString> lastname("Smith”);
>      cell<QString> fullname = surname.lift(
>          lastname, [](QString s, QString l) { return s + " " + l; });
>
>      qDebug() << fullname.sample();
>      surname.send("Emma");
>      qDebug() << fullname.sample();
>
> or (RxJS):
>
>      var surname = new BehaviorSubject("John");
>      var lastname = new BehaviorSubject("Smith");
>      var fullname = new BehaviorSubject();
>      r.combineLatest(surname, lastname).pipe(map(([s, l]) => { return s + " " + l; })).subscribe(fullname);
>
>      console.log(fullname.getValue());
>      surname.next("Emma”);
>      console.log(fullname.getValue());
>
> What is the relation of QProperty to Reactive Programing, in which ways can we orient QProperty on what is done there, or learn from insights in that field?


That's a good question. If you have any insights please share :)

> E.g. what API do you plan for subscribing to value changes of a property (I didn’t see anything in the patch)?


The patch proposes right now an API like this:


     auto subscription = Qt::onPropertyChanged(property, []() { ... });


The function also returns a (moveable) handle that will unsubscribe when 
it goes out of scope. Right now I'm however leaning more towards making 
this a member function of the property again.


> Do you intent to tackle the “missed first event” issue when choosing one? (https://livebook.manning.com/book/functional-reactive-programming/chapter-1/92)


I did not have a specific solution in mind for this. I agree that it's a 
general problem with observers. The same problem exists with signals & 
slots as well -- connecting to a signal after its initial emission. 
Bindings do not have that problem AFAICS.


Simon



More information about the Development mailing list