QUIP 9 | Evolving QList

QUIP:9
Title:Evolving QList
Version:4f29fdd5a9202e41fff8944b25557e0523eddb84
Last-Modified:2021-07-15
Author:Ville Voutilainen
Status:Draft
Type:Informational
Post-History:http://lists.qt-project.org/pipermail/development/2017-March/029040.html
Created:2017-05-15

Evolving QList

Motivation

This quip provides a summary and an analysis of a mailing list discussion about what to do about QList, and how to evolve it going forward.

An original analysis of the issues with QList is at https://marcmutz.wordpress.com/effective-qt/containers/#containers-qlist.

Some emphasis on Marc's findings

As mentioned in the mailing list discussion, at http://lists.qt-project.org/pipermail/development/2017-March/029043.html, QList's semantics and performance heavily depend on the element type. The fact that it might or might not do indirect allocations is a potentially fairly significant performance issue; the fact that it might or might not guarantee reference stability is a potential correctness issue. Arguably, the default container of Qt shouldn't have such pitfalls. It's akin to std::vector<bool>, where some specializations have behavior very different from others.

Main design decisions

Should we have a type named QList?

Marc has suggested to completely get rid of QList, eventually. Getting to that point is not so easy; QList is more or less the default recommended container for Qt code, including libraries and applications written using Qt.

The benefit of removing the type completely would be a loud source-breaking change that arguably tells users to fix their code. The problem is, as hinted at by Martin Smith in http://lists.qt-project.org/pipermail/development/2017-March/029090.html, that code that does what it's designed to do would be broken, and not every user appreciates breaking such code; in fact, quite many don't appreciate it at all.

Should we have an arraylist?

One idea suggested for evolving QList is to just make it an alias for QVector. That takes care of the difference in direct/indirect allocations; QVector doesn't do indirect allocations.

Then the question arises whether we want to have a container that has Copy-On-Write semantics but always does indirect allocation. Such a container has its benefits, as mentioned by Philippe in http://lists.qt-project.org/pipermail/development/2017-March/029045.html and in http://lists.qt-project.org/pipermail/development/2017-March/029294.html. There have been suggestions to use std::vector<std::unique_ptr<Element>>, but that type is not copyable and is not otherwise convenient to use.

What should we do for Qt 5.10?

It doesn't seem sensible to make source-incompatible changes in Qt 5. At most, it seems like we could start nudging our users onto the path forward, but even deprecation of QList may be a bit much. Such deprecation tends to be alarming for casual users.

If we should decide to have a type named QList in Qt 6, we can already start going to that direction; if we plan to make QList an alias for QVector (see next section), we can start by filling in any gaps in QVector's interface so that there's no functionality missing.

If we plan to add a QArrayList, whether just for indirect cases or all types, we can write that type for Qt 5.

What should we do for Qt 6?

We have a couple of approaches:

1) Marc suggests to get rid of QList in Qt 6, effectively replacing it with QVector, and possibly adding a QArrayList that does indirect allocation for types that currently do indirect allocation in QList, and is ill-formed for other types.

2) An alternative approach is to make QList an alias for QVector, possibly adding a QArrayList that is always indirect, but well-formed for all element types. We probably want to deprecate QList in this approach.

The snag about making QList an alias for QVector is that that's not abi-compatible. So a yet another approach would be to keep QList as a separate type, but to make it always allocate in-place rather than indirectly. That would mean QList and QVector are separate types with more or less identical functionality.

Author's recommendation

Here's my personal preference:

1) Fill in the possible gaps in the interface of QVector for Qt 5.10

2) Implement an indirect QArrayList that does indirect allocation for its elements and make it valid for all types, for Qt 5.10

  1. In Qt 6, make QList an alias for QVector and deprecate QList.