[Development] RFC: RAII for property changes

André Somers andre at familiesomers.nl
Wed Apr 15 11:49:56 CEST 2015


Hi,

When writing QObject-derived classes with properties, I often found 
myself writing code like this:

void MyClass::setFoo(QString value)
{
   if (m_foo != value) {
     m_foo = value;
     emit fooChanged(m_foo);
   }
}

Trivial enough, in the simple case. However, when more than one property 
is involved at the same time, or properties depend on each other, things 
can get way less simple and more error-phrone quickly, I found. If the 
order of signals matters (and I found it does some times!), it gets even 
more tricky to get things right. This is especially tricky because you 
really would like to emit the signal at the moment the class is in a 
consistent state. That is, if you have a method that sets both width and 
height of an object at the same time, you really don't want to emit the 
signal about the change of one property before the change of another 
property is also set. In this case, the change may be harmless (but 
potentially expensive, as perhaps two relayouts are triggered when only 
one was needed), but there are cases where you'd really expose the class 
in an inconsistent state if you emit too soon. Considder that at the 
moment you emit, you give other code the change to do whatever its wants 
again, including calling methods on your class, even the very same 
method they just called, or worse, delete it... Your class better be in 
a consistent state when they do such things.

That's why I have been working with a RAII implementation to monitor 
property changes for a while now. The idea is that you instantiate a 
RAII class to monitor a property at the beginning of a method that _may_ 
change the property value, and then do all you want. Upon destruction of 
the RAII class, it checks if the property value changed and if it did, 
emit the associated signal.

The code I now write looks like this:

void MyClass::setFoo(QString value)
{
   PropertyGuard guard(this, "foo");  //foo is the name of the Q_PROPERTY
   Q_UNUSED(guard);

   m_foo = value;
}

which then is further simplified by creating a small macro called 
guardProperty to this:

void MyClass::setFoo(QString value)
{
   guardProperty(foo);  //foo is the name of the Q_PROPERTY
   m_foo = value;
}

Note that you can guard as many properties as you need:

void MyClass::setFoo(QString value)
{
   guardProperty(foo);  //foo is the name of the Q_PROPERTY
   guardProperty(isValid); //the isValid property depends on m_foo as well

   m_foo = value;
}


The PropertyGuard class itself is quite simple in its basic form. It 
uses QMetaObject to read the current value and find the notify signal 
for the property. Upon desctruction, it compares the current value to 
the initial value stored at creation, and if the two don't match, the 
signal is emitted. The code deals with signals with zero or one 
arguments, assuming that in the latter case the one argument is the new 
property value.

I found this little device to be very useful in practice. Not so much in 
trivial setters like the ones on top (but still useful there, as the 
intent is clearer and there is less typing), but very much so in 
non-trivial cases where more than one property may change at a time or 
other complex interactions take place. In cases where a method changing 
should trigger other property changes as well, while not exposing 
inconsistent states of the class I found the device to be extremely 
valuable, as I can be sure that the emits are done at a moment where the 
state of class is fully consistent. I find myself writing emit less and 
less.


So, what are your opinions on using a mechanism like this? I have not 
found it in Qt itself, but perhaps others here are already using similar 
methods or perhaps very different methods to tackle the issues I described?

Looking forward to your comments,


André Somers




More information about the Development mailing list