[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 :)
Thanks,
Marc
--
Marc Mutz <marc.mutz at qt.io>
Principal Software Engineer
The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io
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