[Development] Notes on QtCore session @ QCS2016

Kevin Kofler kevin.kofler at chello.at
Tue Sep 6 19:52:01 CEST 2016

Giuseppe D'Angelo wrote:
> So please do not derail this sub-topic. The subject at hand here is
> using Standard Library datatypes in our public API.

And I was just pointing out that doing so also waters the API consistency, 
in addition to the ABI issues.

> 1) BECAUSE. THEY. ARE. NOT. BETTER. In so many cases they're actually
> far worse (hi, algorithms!). Can we please stop having this discussion
> over and over again?

QtAlgorithms was more convenient to use than the STL algorithms. In 
particular, it had convenience overloads operating on the whole container, 
which is by far the most common use case, whereas the STL algorithms require 
you to copy&paste begin() and end() boilerplate.

Both the Qt and the STL implementations of things have their advantages, but 
as an API user, I find the Qt ones much more compelling than the STL ones. 
One important property is that the Qt ones are usually a lot harder to 
misuse in a way that will make them very inefficient (e.g., O(n) by-value 
assignment of std::vector vs. O(1) by-value assignment of QVector or QList, 
O(mn) insertion into std::vector vs. O(n) insertion into QList, etc.) or 
even crashy (e.g., accidentally modifying a container within a range-for on 
it vs. safe Q_FOREACH). The STL ones may be marginally faster when used 
perfectly, but it is hard to get everything right (and requires ugly write-
only hacks such as move and swap), and even the slightest mistake will more 
than kill the performance advantage.

The Qt containers are what makes C++/Qt competitive with other languages in 
term of convenience. In fact, in terms of convenience, I'd easily rank
Qt > Java > STL. Forcing people to use the STL will just make them prefer 
languages with a less arcane standard library.

> 2) Because there are countless things for which you can't escape from
> using the Standard Library: how can you possibly implement things like
> std::is_enum? How can you handle initializer lists? (And yes: we need
> all of that).

In the public API, non-optionally?

> 3) Because nobody wants to spend time to properly reimplement
> non-trivial things like std::function, when we have a fully working
> std::function we could just use. And we need std::function in many
> places in our public API. Rinse and repeat for the other cases.
> And before you think of "let's make a simplified std::function, which
> will be 'simpler' for the user to use, and 'simpler' for us to
> implement", please read
> https://www.kdab.com/goodbye-q_foreach/#comment-158485

And that is exactly one of the comments I disagree with. (In fact, I had 
posted a reply to that blog comment, but it was censored by the blog owner.)

The premise there is that we want to eventually deprecate things like 
qAsConst, and so we have to artificially cripple them to allow doing that in 
the future? But why can we not just accept to keep a better version forever? 
So the entire premise is wrong.

As for the issue of avoiding copying non-implicitly-shared rvalues: Would 
this work?
#define qAsConst(x) static_cast<const auto &>((x))
As far as I know, rvalues can (still) be safely cast to const T &.

>> What benefit does it bring to users to deprecate nice APIs for less nice
>> ones just because the latter are part of the compiler?
> Nobody is talking about this -- on the contrary, we even considered
> offering convenience classes. Say, a std::vector subclass which adds
> append() and isEmpty().

That doesn't solve the inherent lack of COW. It is possible to wrap COW 
around STL containers (e.g., I've done so for std::priority_queue in a 
project of mine), but that adds an extra indirection compared to QVector, so 
it is a performance loss.

        Kevin Kofler

More information about the Development mailing list