[Development] How qAsConst and qExchange lead to qNN

A. Pönitz apoenitz at t-online.de
Sat Nov 12 14:41:39 CET 2022


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.

> 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,

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

> 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.

[Within a function, or a private class, or to access external functions
it's of course fine to use anything that fits and this can be
micro-optimized at will]

> All other cases look much fuzzier to me. QSpan or QStringView (or a
> generator) may be beneficial or detrimental there, depending on exact usage
> pattern.

Right.

> The cost we're avoiding is mostly the reference count, a far cry
> from a deep copy. On the flip side we're introducing complex life time
> problems that will lead to hard to find memory management defects. I suggest
> we look at this from the perspective of a _user_ of Qt. I'm pretty sure you
> can all imagine which problem a user would prefer here.
> So, I suggest we add those "view" APIs to the cases where they provide a
> clear benefit.

Right.

But we should to spell out what "clear benefits" means. I /my/ world it
would not be sufficient to give examples of cases where it helps, but
also need weighing with the expected frequency and against the
(potentially, not necessarily exitsting) costs for other/"normal" users.

> For methods that return a span/view/generator, we should
> always offer a safe alternative that returns an owning container. The naming
> convention should be:
> 
> 1. Use overloads for methods that take views or spans.uIn new API we can
> omit the methods that take owning containers.

I am not sure that in the typical case a span-only is a benefit. As said
before, this leaks implementation details into the API and pessimizes
the case where the user /has/ a container.

> If the overload set grows out
> of hand, don't add the view/span alternative until we can remove something.

I oppose any scheme that makes removal of API a common case or part of
the overall scheme.

> By Thiago's argument, that means not to convert existing methods to
> QStringView for now.

That at least, right.
 
> 2. Use the postfix "View", "Span" or "Generator" for methods that return
> views, spans or generators rather than owning containers. This way it's
> harder for users to mess up the life time.

That's fine.

Andre'


More information about the Development mailing list