[Development] QList

Marc Mutz marc.mutz at kdab.com
Sat Mar 18 18:37:15 CET 2017


Ville,

A word of warning: when it comes to QList, there's a very vocal minority that 
claims that either QList works perfectly well or else ain't so bad. But 
afaict, there's consensus between the people who actually count (sorry to be 
blunt, but Qt is not a democracy, but a meritocracy) that QList as-is 
currently was a mistake and needs to go in Qt 6. The only difference in 
opinion is how to cushion the fall.

Lars, Thiago: it would be nice if you could confirm (or deny, in case I 
misinterpreted) the above as soon as you can. Otherwise this thread will 
derail massively again.

On Saturday 18 March 2017 11:25:12 Ville Voutilainen wrote:
[...]
> > Kill QList in Qt 6.
> 
> How much valid code will that break? How many bugs does that avoid?

Tons. Qt uses QList as the default container since Qt 4.0. Before, it used 
QValueList, a doubly-linked list. Qt has a very bad track record for its 
default container choice.

We do need to think very carefully about an exit strategy, indeed. What I 
wrote in the mail you quote from was the part that deals with not introducing 
new uses of QList. We need also deal with existing use, even though we can 
hope for clang-based refactoring tools to do the bulk of the work.

But we simply cannot, in 2020, continue to use a 
std::vector<std::unqiue_ptr<T>> as our default container. That's simply 
ridiculous.

> > This experience, over several years, has thaught me that we need a
> > technical solution. And so we started to specialize QList<QNewType> as
> > an empty class. So far, this is the only workable solution I have found,
> > and believe me, I am very determined.
> 
> As a technical point, reminding me of how std::hash is 'poisoned', and
> why std::experimental::fundamentals_v2::nonesuch
> exists, you might want to also prevent default construction, copy/move
> construction and copy/move assignment.
> Otherwise an innocent user might create an object of such a type, pass
> it into a generic function and
> get a fairly unwelcoming error deep in an instantiation chain.

Keep that in mind. You'll almost certainly be reviewing any such changes.
 
> > So, here's my proposal for a QList exit strategy:
> > 
> > In Qt 5:
> > 
> > 1. Replace QList in generic code by QListOrVector, tell users to hold
> > QLists
> > 
> >    they get from Qt API only in type-deduced variables.
> 
> In other words, introduce generic code where there wasn't generic code
> before - users writing
> non-generic code calling non-templates that return QLists will need to
> use deduction or a metaprogramming tool.

No, that is false. You can keep using QList for now everywhere you used it so 
far, in non-generic code. Nothing changes for existing types. And for new 
types, the compiler will make sure that you don't get away with QList. We do 
recommened to use auto to receive QLists to avoid having to port these code 
lines manually come Qt 6. I do not consider auto variables "generic code".
 
> > 2. Fix any QList API missing (and not actively harmful) on QVector. E.g.
> > I
> > 
> >    don't think toSet() should be either on QList nor QVector, because it
> >    creates nonsense like qHash(QItemSelectionRange) (please, please, look
> >    it up :)
> > 
> > 3. Disable QList for all new QFoo value types (by specializing
> > QList<QFoo> as
> > 
> >    an empty class).
> > 
> > 4. Provide QArrayList for code that needs stability of references
> > (stability
> > 
> >    statically checked in Qt 5, enforced in Qt 6).
> 
> It seems that (4) is perfectly safe, whereas (2) and (3) are breaking
> changes; to what extent, I would like to know.

(2) is possibly breaking, yes. We should intercept by deprecating 
QList::toSet() and re-adding it as a free function.

(3) is breaking nothing for existing code, since it only applies to new types. 
New types don't magically show up in your source code. You have to introduce 
them yourself. As for existing generic code, it's a source-incompatibility 
that is accepted, because it can be fixed by using auto variables. Or you 
don't use the new type at all. I mean, we're not talking about QString here. 
With very few exceptions, any type we're adding now will not get widespread 
use before Qt 6, anyway. One exception hopefully being QStringView.

> > In Qt 6:
> > 
> > 5. Replace all QList uses left with ... what ? QVector? std::vector?
> > 
> >    -> separate discussion
> > 
> > 6. Kill QList or keep it as a deprecated class.
> 
> This certainly seems feasible, but the migration and the extent of it
> its interesting. There's a fair bunch
> of QList-using code out there, afaik.

Indeed, if it was easy, it would have been done long ago. But it's nonetheless 
absolutely necessary. Q6String will not fit into a QList anymore. QVariant and 
QModelIndex already don't. And given the extensive use of QVariant in QML/Qt's 
property system, I don't think anyone can be happy about the per-element 
memory allocation in QVariantList.

Thanks,
Marc

-- 
Marc Mutz <marc.mutz at kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
Tel: +49-30-521325470
KDAB - The Qt, C++ and OpenGL Experts



More information about the Development mailing list