[Development] How qAsConst and qExchange lead to qNN

Volker Hilsheimer volker.hilsheimer at qt.io
Mon Nov 14 17:54:20 CET 2022


> On 12 Nov 2022, at 14:41, A. Pönitz <apoenitz at t-online.de> wrote:
> 
> On Fri, Nov 11, 2022 at 09:35:27AM +0100, Ulf Hermann via Development wrote:
>> There is an undeniable benefit of _offering_ QSpan, QStringView, and
>> generator APIs in a few relevant cases:
> 
> This is true, but my problem with this is that already _offering_
> additional solutions does not come for free: It bloats the API,
> it bloats docs, introducing the first overload is SIC etc.


With QT_REMOVED_FROM we can remove the “first overload” problem, and replace QString with QAnyStringView.

We could use QAnyStringView  in e.g.. QFont::fromString or QPageRanges::fromString or QKeySequence::fromString (the obvious candidates in Qt Gui). And then I can write either of


fromString(“foo”);
fromString(u“foo”);
fromString(u"foo”_s);
fromString(stdString);
fromString(qString);

Is that not a good idea?

Perhaps it isn’t because there is now a fraction of our API that I can call that way, why for the vast majority I have to always use Qt::StringLiterals and call with a u”…”_s.

But how can we make progress with our API otherwise? Should we accept that we will never be able to call a QString-taking setter with u”…”?


>> 1. Users want to pass a "foreign" container to a Qt function that doesn't
>> only store it as QList or QString. It might merely iterate it or store it as
>> something else.
> 
> Tradionally, we had QList as the (designed to be, and in practice also
> being) the "usually good enough for most uses" container, so in a /Qt/
> World, this "alien container" case /practically/ had no relevance,


I don’t think we can be certain that the amount of client code that use non-Qt containers and only deals with Qt containers at the API boundary is negligible. I would rather assume that only a minority of Qt applications *only* use Qt. The slice of the world that truly is a “Qt World” is perhaps rather small, while the majority of applications is a messy, organically grown mix of different frameworks and libraries. In those, most thing are alien to most other things, and interoperability on various levels is important.

So making it convenient for client code to use Qt APIs without having to deal with Qt containers has value. It is possible today - although perhaps under-documented, esp since we removed to/fromStdVector and to/fromStdList from Qt 6:

    setList({svector.cbegin(), svector.cend()});

This is not great, but as long as client code is anyway operating on owning containers, it’s perhaps as good as we can reasonably make it.


> The problem of regularly having to convert between Qt containers has been
> /introduced/ by people advocating QList uses by QVector, or std::vector.


Qt 3’s QValueList was implicitly constructible from std::list. We added it because people asked for easier integration of Qt with STL-using code.


>> 2. Assume a container that isn't internally stored as QList or QString, but
>> is returned from a Qt function. Users want to use that thing as something
>> else than QString or QList. For example they might merely iterate it or
>> store its contents in a "foreign" container.
>> 
>> In those cases, using QList or QString as transfer mechanism induces an
>> unnecessary deep copy.
> 
> This is pretty much the same problem: Standardizing on QString and QList
> as the "primary" containers avoids these problems on a large scale,
> and this overall gain outweighs the effect local micro-optimizations
> by far. The problem is that this (un-)balance is hard to communicate,
> as it is very easy to demonstrate that small, isolated uses of QString
> and QList are suboptimal, but the /overall/ benefit of a uniform
> approach only kicks in at "real world"-sized applications.



For applications that are not “pure Qt" applications - and I believe that is not an insignificant number, perhaps it’s even the majority - standardizing on Qt data types is simply not an option.

And Ulf’s case here is anyway that “there is no QList or QString” that is internally stored and that we just need to return. There might not even be any list-or string-like datastructure stored.

QItemSelectionModel doesn’t store a QList of selected indices. And yet QItemSelectionModel::selectedIndexes returns a QModelIndexList that is rather costly to create. An application that just wants to iterate over all selected indexes already has to pay an unnecessary cost. An application that then doesn’t use Qt containers in client code pays an extra cost on top.

I think it would be good if we could develop an API strategy that avoids that. Marc’s proposal of a Non-Owning Interface is already become manifest in QRegion::begin/end

https://doc.qt.io/qt-6/qregion.html#begin

allowing us to write


for (auto rect : region)
   doSomethingWith(rect);


(while QRegion::rects will have to create a QList even if there is only a single rect in the inline storage, which is then not a QList).


This is a *good* addition to Qt. I think we can make more such additions to Qt, in places where it makes a real difference for today’s client code using owning containers, and without changing the world.


Volker




More information about the Development mailing list