[Development] How qAsConst and qExchange lead to qNN

Marc Mutz marc.mutz at qt.io
Tue Nov 15 09:52:24 CET 2022

On 15.11.22 08:14, Ulf Hermann via Development wrote:
>>> So, if the method immediately converts whatever it gets to QList or
>>> QString, then there is no point in passing it a span or view.
>> My point is that there _is_. Citing my blog post:
>>     callConsumeQStringHelloWorld():
>  > [...]
> That's the worst case scenario of passing an 8bit string literal to a 
> function that takes a QString. We have QStringLiteral to avoid the 8bit 
> to 16bit conversion, but I know there are more problems with that.
> Now lets look at the case of passing a pre-existing QString (i.e. one we 
> don't have to create in place) to a function taking QAnyStringView and 
> storing the result as QString.
>      // somewhere:
>      QString a;
>      void setter(QAnyStringView view) { a = view.toString(); }
>      // elsewhere:
>      QString foo;
>      [ ... modify foo ... ]
>      setter(QAnyStringView(foo));
> That's a deep copy. A deep copy of a string is obviously more expensive 
> than the overhead of calling the QString ctor and dtor.

That remains to be proven. A rule of thumb for atomics is that they're 
two orders of magnitude slower than a normal int. They also still act as 
optimizer firewalls. With that rule of thumb, copying 50 char16_t's is 
faster than one ref-count update. What really is the deciding point is 
whether or not there's a memory allocation involved. I mentioned that 
for many use-cases, therefore, a non-CoW SBO container is preferable over a CoW 
non-SBO one.

If QString and QByteArray had both efficient substringing and SBO, my 
arguments would carry much less weight. But we have neither, and adding 
it (esp. SBO) to QString for Qt 7 will break users, silently. Therefore 
it's prudent _not_ to change QString, but to add QSmallString or 
something instead. Until then, u16string and QVLA<char16_t> can be used, 
by users and implementations.

Any way you turn it, non-owning containers in the API make for long-term 
stable APIs even as we improve our container classes in incompatible ways.

> Which case is 
> more common? And by what factor?
> I can't say what case is more common. What I can say is that the risk of 
> creating deep copies sounds worse to me than the risk of calling the 
> QString ctor and dtor too often.
> This is what I mean with "fuzzy". We don't really have the data to 
> support a move to QAnyStringView for all of our API.

I can say with firm belief that, _atm_, passing QString is more common. 
But this is a self-fulfilling fact. The tst_qsettings experiment shows 
what can happen if you port an API that doesn't naturally receive 
pre-made QStrings.

If you want to take a peek at a world without owning containers, use the 
Qt 6 QXmlStreamParser API or llvm.

With the caveat that the problem with QXmlStreamParser is that it needs 
to convert to UTF-16. The vast majority of XML data is _not_ in UTF-16. 
If QXmlStreamReader's API was formulated in QAnyStringView, it wouldn't 
have to. We could just mmap() files and hand out QAnyStringViews to 
tokens. Not going into whattaboutism here, but what about all those 
unnecessary encoding conversions? Each one is a deep copy, too. UTF-16 
is a total alien in the Unix world, and, connecting to your world, I 
think it's safe to assume that very few QML files are encoded in UTF-16, 
either. And PySide string are also not encoded in UTF-16, I think.

But UTF-16 is sacrosanct in Qt. It's a cult. Irregardless of how many 
deep copies it takes to convert to and from UTF-16 from native 
encodings, people still worship it as god-given. It's not.

No-one would use Clang if it internally converted everything to UTF-16 
first. It would be too slow.

QAnyStringView, QUtf8StringView and, later, QAnyString, QUtf8String, can 
be used to to make UTF-8 a first-class citizen in Qt.

Likewise, owning containers are also sacrosanct in Qt. They're a cult. 
Irregardless of how many deep copies it takes just to call a Qt function 
from Python, Java/Script or QML, people still 
worship them as god-given. They're not.

There's nothing inherently Qt-ish about owning containers. Qt is all 
about allowing developers to write great applications across platforms. 
Ideally, we'd focus on picking up developers where they come from. That 
means instead of inflicting a Java-ish C++ API on Python programmers, we 
make PySide rock by minimizing copies between Python and Qt/C++ data 
structures. iow: NOI.

Guys, take the blinkers off :)


Marc Mutz <marc.mutz at qt.io>
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

More information about the Development mailing list