Qt World Summit: Submit your Presentation

QList append() is implemented as extend instead()

  • The existence of the QList<T> overrides for append, << and += effectively turn append() into an extend() operation when using lists of the same type.

    void QList::append(const QList<T> &value)
    QList<T> &QList::operator<<(const QList<T> &other)
    QList<T> &QList::operator+=(const QList<T> &other)

    First off, why would it be implemented like this? The docs mention that this was added in 4.5, but not why and I haven't been able to find any documentation on why, which is frustrating when I have a large existing code base I'm trying to update from pre-4.5 to 5.x+ and it assumes in a great many places that append (<<) actually means append, and not extend.

    Clearly someone on the Qt team thought that it would be a convenient behavior, but I can't imagine why.

    Secondly, what, if anything, are my options for fixing up my code base, beyond littering it with ugly QVariant() wrappers around all the lists and re-training all the devs on our team to not trust append anymore:

    // Arbitrary simple example, using a typedef because the vast majority of our project does something like this using a typedef in a toolkit module for convenience
    typedef QList<QVariant> VList;
    VList list_a;
    VList list_b;
    list_b << "some" << "stuff" << 55 << 4.0; // Random things for example
    list_a << "foobar" << QVariant(list_b) << endl; // Must wrap in QVariant so list_a isn't extended by list_b
    list_a.append(QVariant(list_b)); // Even must wrap in QVariant when called explicitly to not get extend behavior, which is blatantly wrong from a logical/naming standpoint.

    The research I've done so far suggests that taking the "QStringList" route and inheriting from QList is not encouraged due to QList not being set up correctly for inheritance (and I've seen comments saying that QStringList will be "fixed" to not inherit from QList in 6.x). http://stackoverflow.com/a/17929800/5549059

    Not wanting to wrap thousands of places in QVariant basically leaves 2 option that I can see, change our VList into it's own class that contains a QList<T> and fix append() only on VList, or create some sort of 'actualAppend()' extension function (which will be basically as bad or worse as wrapping in QVariant for readability but an improvement for understandability when reading code (probably)).

    I'm leary to change the QT Source locally to properly append instead of extend, because it's existed in this form for so long that some place in the QT Core source likely relies on this behavior. (I would hope, otherwise, why make the change in the first place?)

    Creating a fully functional wrapper class that will play correctly with QVariant that I will have to maintain into the foreseeable future is beyond what I want to do, but would be the cleanest way if I could pull it off, assuming we never use QLists directly. Do I have any reasonable options other than forcing everyone on the team to learn that append isn't always append in Qt from now on and writing static analysis tests to catch as many 'incorrect' uses as I can?

    Is the Qt team happy with this decision in general? Do I have any chance of convincing anyone to fix the misleading behavior? If I choose 'wrapping in QVariant()' as my fix will that fix actually be supported in the future? Or will some ambitious Qt dev 'fix' append to be extend in that scenario also someday?

    Can anyone think of a better, or more obvious solution that I've overlooked? Most of our existing problem areas are using our typedef type and the << syntax, for what it's worth.

    The change is frustrating to me since I can't see the benefit of it outweighing the problems it causes, though I realize I must be in a minority since it has persisted for so long.

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    That's a pretty interesting analysis but you're on the wrong place to be heard by the Qt developers.

    You should bring this to the interest mailing list. You'll find there Qt's developers/maintainers. This forum is more user oriented.

  • Moderators

    I can't say why it is the way it is or is it good or bad. I can see arguments for both possible implementations. I'd be interested to see the reasoning for this particular decision too.

    Anyway... to tackle the existing problem - you don't need to modify Qt source or subclass. QList is a template. Just specialize the case you want to do what you want i.e.

    #include <QList>
    QList<QVariant>& QList<QVariant>::operator<<(const QList<QVariant>& list)
        return operator<<(QVariant(list));

    Same for operator+= and other containers. Put that somewhere globally accessible (like a precompiled header if you use one) and you should be good to go.
    The ugly thing about it is that it changes the documented behavior (even though that's actually what you want), so people looking it up in the docs might be surprised that it behaves differently. Be sure to document this behavior in some visible way if you decide to do this.

Log in to reply