[Development] How qAsConst and qExchange lead to qNN

Marc Mutz marc.mutz at qt.io
Tue Nov 8 22:20:29 CET 2022


Hi Andre,

When you say

 > You, /personally/ /you/, have been the driving force

I think you and Kevin are giving me credit where none is due. The Qt 
containers changed multiple times before the Qt project was even formed 
and yours truly could have possibly had any influence on their design.

Interestingly, when you say

 > Staying with unmodified Qt 4 containers would very likely just have
 > worked in Qt 6 and not have caused any problems for users upgrading

Two things spring to mind:

First, that it's probably not a coincidence that stability came right 
after Qt adopted basically the STL model. QVector was std::vector + 
COW, QMap was std::map + COW, and the old QGList experiment was finally 
put to rest as Q3PtrList.

Second, that I completely agree with you. I think the decision to make 
Q6List be Q5Vector and add a prepend optimisation was a major mistake. 
We should have told people to prepare for QList -> QVector by using auto 
when receiving QLists from Qt, added implicit conversions between them
for when users were passing in QLists, and then we should have cleaned _our_ 
basement by porting away from QList to QVector (we anyway did that), but 
leave Q5List as-is in qt5compat. I think you will find me and Peppe on 
record on this mailing list in the run-up to Qt 6 asking exactly that. 
Alas, TPTB decided, instead, to

- reuse the QList name for QVector
- _not_ provide Q5List in qt5compat

thus breaking not only our own uses (which we had to do, anyway, in the 
move from QList to QVector), but also our users' code. Silently, I 
hasten to add.

Finally, when you say

 > I haven't checked
 > explicitly, but my best guess is that Qt 4.0 (2005(!)) would
 > container-wise be "good enough" for my current needs.

We're in violent agreement, too. Why take them from someone for whom the 
Qt4 containers are good enough™? From my pov, the Qt containers can be 
moved into a libQtQTL or something like that and enjoy their life as a 
slightly different approach to the STL containers. Then users that don't 
need Qt per-se could opt-in to using the Qt containers _only_ (and a 
similar argument can be made for the Qt string types; libQt7Strings; 
CopperSpice says to say hello), potentially drawing in more users, if 
they, indeed, serve a different audience than the STL ones.

What I _do_ care about is that Qt atm doesn't let the user /choose/. 
Because of their ubiquitous use in Qt APIs, the user is forced to use 
the Qt containers, even though he may have a need for the STL containers 
(interop with 3rd-party libraries, allocators, > 2Gi elements, etc).

I don't want to take the Qt containers away from Qt users. I want to get 
rid of their use in our APIs, so that both the Qt implementation as well 
as our users are free to choose the best container for their needs 
instead of having to pick from one of the public Qt containers.

Let each user choose among the Qt, STL, Boost, Abseil, and Folly 
container classes on a level playing field.

Now, if you like an intellectual challenge, the please explain to me how 
Qt's insert-or-assign is either more convenient, easier, more 
user-friendly, more idiomatic, or whatever, than STL's insert-or-no-op 
If, as you say, the Qt containers are carefully designed to a different 
set of goals, then I'd really like to know what the goal looks like that 
made Qt choose this design.

To summarize:
- I will not accept responsibility for any container rewrites in any of
   the Qt major version changes. I was not involved in any of these
   decisions, and where I was involved in the discussion, my suggestions
   were not followed.
- I do not want to take Qt containers away from Qt users. Instead, I
   want our APIs to stop forcing our users (and us) to use (owning) Qt
   containers.

Finally,

 >> Q_FOREACH
 > [I can make 100% correct predictions about changes I intent to push,
 > too. What's the point?]

I have no desire to touch the implementation of Q_FOREACH, ever. I did, 
unwillingly, when its users suffered unnecessary pessimisations in the 
past, but the port to C++20 ranged-for-with-init is not of that kind.

 > string UDLs

 From my POV, we were fixing up a prior experiment-gone-wrong. I laid 
out the problems of the _qs UDL design in 
https://lists.qt-project.org/pipermail/development/2022-March/042335.html, 
so I won't repeat them here.

Thanks,
Marc

On 08.11.22 20:32, A. Pönitz wrote:
> On Mon, Nov 07, 2022 at 08:15:58PM +0000, Marc Mutz via Development wrote:
>> Hi all,
>>
>> SCNR taking the proffered bait:
>>
>> On 07.11.22 18:51, Edward Welbourne wrote:
>>> For Qt to remain relevant in the rapidly-evolving C++ landscape, it
>>> needs to change; but one of its strong selling-points has long been its
>>> conservatism in API and ABI, that lets working code keep working.
>>
>> I've not been around for the Qt 1 → Qt 2 port, but I did participate in
>> all of the Qt 2 → Qt 3, Qt 3 → Qt 4, Qt 4 → Qt 5 and Qt 5 → Qt 6
>> transitions. Speaking with my Qt user hat on, I'm terribly sorry to
>> inform y'all that Qt has largely _failed_ to keep working code working.
>> Sure, a trivial QWidgets program from the mid-90s may still compile and
>> work in Qt 6, but as soon as said program touches Qt container classes,
>> it's game over.
> 
> Staying wiht unmodified Qt 4 containers would very likely just have
> worked in Qt 6 and not have caused any problems for users upgrading
> their applications during the last 15 years.
>   
>> Both Boost and C++ itself have a much better track record of keeping
>> working code working, let alone any random C library. And this is
>> actually a fair comparison, because we're comparing apples (STL
>> containers) to apples (Qt containers).
> 
> No. Goals of STL and Qt containers are /quite/ different.
> 
> Qt offers convenience and ease of use while still being "good enough"
> at performance for normal use. STL can give better performance in some
> cases, but needs more handholding, more alertness from the user, and
> it's easier to get things completely wrong, also performance-wise.
> 
> This is absolutely not "apples vs apples", rather (tr("Nicht alles, was
> hinkt, ist ein Vergleich, aber:")) "cars vs motorcycles": Sure, they have
> a lot in common, but none is uniformly "better" than the other.
> 
>> Let's not kid ourselves thinking Qt is any special here. It isn't. We
>> mustn't just look at one major release cycle. Qt loses projects at every
>> new major release, because changes to non-core-competency parts of the
>> API make porting unnecessarily complicated, so that unmaintained or
>> understaffed projects[1] cannot muster the strength to be ported.
> 
> I consider this an absurd line of reasoning coming from /you/.
> 
> You, /personally/ /you/, have been the driving force behind a
> significant amount of /from my perspective/ unnecessary and absolutely
> unwelcomed changes like the removal of Q(5)List that I predicted to be
> and now apparently _is_ hampering "understaffed projects" (which in my
> book covers pretty much /every/ open source projects and quite a few
> commercial ones) to move from Qt 5 to Qt 6.
> 
> This "loss of projects" is not the consequence of any natural law or
> divine intervention. Even "understaffed projects" can typically "muster
> the strength" to do _necessary_ adaptations to _critical_ problems.
> However, it is completely no surprise _to me_ that they do not want to
> jump through any hoop that is effectively only busy-work, not solving
> any real problem.
> 
>> My goal with qNN is to make porting away _simple_. All that's required
>> is to s/qNN::/std::/ and be done. No deprecation, no sanity bot, not
>> even the need for local code knowledge; just simple global textual
>> replacement. And no regressions, if you first switch to C++NN, and only
>> then do the replacement. We can even retain the qNN symbols until Qt
>> requires C++(NN+3), because the qNN headers will be nothing but a long
>> list of using std::foo; at that time.
>>
>> It's not really acceptable that such trivial ports should be subjected
>> to all the same (or, apparently since it's done in bulk, more
>> restrictive) requirements than for deprecation of core-competency APIs.
>> The more so as I must have missed the outcry of developers when we inflicted
> 
> _To me_ it is not really acceptable that (parts of) qtbase are treated
> as playground for experiments. [And _I_ _do_ think that e.g.  calling
> "string literal qualifications du jour" that barely last for a year "an
> experiment" is fair].
> 
> In my world, deprecations ("trivial" or not) _in a library_ should only
> happen as a consequence of an unexpected _and_ fundamental _and_ otherwise
> unfixable flaws in the API, causing _real_ (not "imagined") harm for "a
> lot" of users. This should never be used wantonly, and definitely not
> pre-planned.
> 
>> To hold users, a project must maintain _long-term_ API stability, not
>> rewrite the container classes for every major release.
> 
> ... grrrr ...
> 
>> So, sorry, but as a user of Qt I'd really like to use those stable STL
>> classes, if only your volatile APIs let me. I'd rather I had done that
>> _one_ port between Qt 1 and 2 than all those ports in Qt 1-6.
> 
> Again, /you/, /personally/ /you/, have been /actively/ involved and
> promoted and/or done part of these /breaking/ changes. I haven't checked
> explicitly, but my best guess is that Qt 4.0 (2005(!)) would
> container-wise be "good enough" for my current needs. And it's not that
> STL has't changed since then...
> 
> [And just to make sure: With "current needs" I herewith take the liberty
> to not speak just for my personal one or two hobbyist projects using Qt,
> but also for my day time job.]
> 
>> Well, as they say, if 20 years ago was the best time to do the switch,
>> then the next-best time is today[2].
>>
>> Anyway; to all those who disagree when I say Qt should concentrate on
>> its core competencies and stop meddling with container classes, shared
>> pointers, etc, I say this: which of the two universes above would you
>> rather have lived in these past 30 years? A or B? Be truthful!
> 
> I prefer a universe where people work towards a common goal. If there
> are fundamentally incompatible goals (as apparently the case here), I
> tend to prefer the goals that the vast majority of "neighbours" in this
> context prefer -- or I leave the context.
> 
> I was happy enough (and still am...) using Qt. The most distracting
> issue on the pure technical side for me is this attempt to "de-Qt" Qt.
>   
>> Because, you see, whenever we phase out some Qt NIH API,
> 
> [And since we are at it: It would ease my life (but possibly hamper the
> life of my cardiologist) if you wouldn't call it "Qt NIH API". This is
> an open insult to people who actively designed these APIs _with
> different goals_ than the STL. I personally think it's completely fine
> if you don't agree with these different goals, but then please accept
> that these goals exist, too]
> 
>> we beam a small part of your (and our!) code from Universe A into the
>> Universe B. I _really_ can't understand why anyone would complain.
> 
> I am typically completely fine with people holding different opinions than I,
> related to code or otherwise. I occasionally even find it interesting to
> discuss certain issues beyond the point of "I accept that you have a
> different opinion", most notably if that opinion can be expressed as the
> logical consequence of certain axioms - and that's even independent of
> whether these axiom are or are not relevant in /my/ world.
> 
> I do, however, complain when something is needlessly causing busy-work
> for me that doesn't fix any of my problems. And that is definitely the
> case here.
> 
> Andre'
> 
> PS:
> 
>> Must be a case of recency bias or something like that...
>>
>> Speaking of the devil, from my pov, qAsConst isn't "small enough" to
>> survive. Fighting off patches that try to make the deleted rvalue
>> overload "do something" is _also_ maintenance work, even if it doesn't
>> result in a code change.
>>
>> Finally, I'll bet my behind (pardon my French) that at some point in
>> the not-too-distant future someone will appear on Gerrit with a patch
>> to change Q_FOREACH to use C++20 ranged-for-with-initializer:
>>     #define Q_FOREACH(decl, expr) \ for (const auto _q_foreach_c =
>>     expr; decl : _q_foreach_c)
>> And I'd probably approve it, because then that thing can actually just
>> be replaced with the expansion everywhere, and then, finally, be
>> deleted.
> 
> [I can make 100% correct predictions about changes I intent to push, too.
> What's the point?]
> 
-- 
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