FEB
20
2007

More KConfig love

I wanted to use the title "merged kconfiggroup_port branch", but I think I should learn from Aaron, so there we go :)

It all started by a bug David fixed in kmail:

KConfig *config = giveMeRandomKConfigObject();
config->setGroup("Hallo");
config->readEntry...

And ouch - the random kconfig object has a different group now. Harmless? NO! Because other code in KDE simply does readEntry without setting the group everytime, or you have setGroup calls all over the place. Beside such easy to fix (but hard to find) bugs, it's pretty hard to write thread safe API if you have to rely on a group element in KConfig.

A solution for this problem was created for KDE 1: KConfigGroupSaver, but it's just a work around for code forgetting to reset the group to it's old state. And of course it still relies on setGroup - it just hides it:


KConfig *config = giveMeRandomKConfigObject();
KConfigGroupSaver gs(config, "Hallo");
// of course make sure not to pass config to other functions in here
// that do not use KConfigGroupSaver
config->readEntry...

So Nov 2001 KDE 2.2 introduced KConfigGroup, which makes it possible to use KConfig without relying on its group element. A KConfigGroup is an object that encapsulates a group in a KConfig without changing that KConfig object, so your code becomes


KConfigGroup group( giveMeRandomKConfigObject(), "Hallo");
group.readEntry...

And this makes it possible to read from two groups of the same config file at the same time without setGroup calls before every second readEntry call.

But sad news: this class was used about 10 times all over KDE 3 even though it's so much simpler and much more consistent in its use. So I decided to bite the bullet and deprecate setGroup calls and make sure it's not required for kdelibs usage. Because our API had bad mixture of how they expect their KConfig objects. Just two examples:


/** overload, but don't change the group - it's set correctly */
readProperties( KConfig *config );

/* This method does not effect the active group of KConfig. */
loadEntries( KConfig *config, QString groupName );

Both use cases just cry for passing a KConfigGroup object - and so they do now for KDE trunk. But of course there is still a lot of setGroup going on (1757 according to my latest log statistics), so if you see a warning from your compiler that setGroup is deprecated, please port your code (I ported already use cases a script could interpret).


// old code
config->setGroup("General");
config->writeEntry("Key", 0);

// new code
KConfigGroup cg(config, "General");
cg.writeEntry("Key", 0);

// alternative (addition to the API)
config->group("General").writeEntry("Key", 0);

Comments

Could you further explain the problems with the example code in kmail? Is the main bug that one forgets to call setGroup while fetching an entry? How does this relate to your remark about thread-safeness?


By ponto at Tue, 02/20/2007 - 13:22

The problem comes from calling functions that set the group but do not reset it. Every function in itself then looks like this:
function() {
config->setGroup("aa");
config->writeEntry("key", 0);
anotherfunction();
config->writeEntry("aa", anotherfunction());
}

Looks correct, but is wrong if anotherfunction follows the same construct


By Stephan Kulow at Tue, 02/20/2007 - 13:33