[Development] RFC: Containers member functions for algorithm

Eike Ziller Eike.Ziller at qt.io
Thu Mar 23 09:27:53 CET 2017

> On Mar 23, 2017, at 8:32 AM, Olivier Goffart <olivier at woboq.com> wrote:
> Hi everyone,
> I have been wondering if we should enhance Qt container with member functions 
> to help using some of the standard algorithm.
> a peace of code is better than many words. We would be able to do:
> myList.sort();
> //or 
> myList.sort([](auto &a, auto &b){ return a.member < b.member; });
> if (myList.contains([&value](const auto &elem){ return elem.id == value; }))
>   doSomething();
> myList.removeIf([&](const auto &elem) { elem.field > someValue; })
> And these are a tad more convenient than using the standard library directly.
> Compare to:
> myList.erase(std::remove_if(myList.begin(), myList.end(), 
>                  [&](const auto &elem) { elem.field > someValue; }),  
>                 myList.end());
> Of course, myList can be a QList, a QVector, or a QVarLenghtArray
> Here is an overview in how this could be implemented, should we want this:
> https://codereview.qt-project.org/#/c/189313/
> Anyway, before I continue working on this patch, I want to know if this is 
> even something what the Qt Project wants.
> The reason we would want it are obvious: convenience.
> In the mean time, the standard is working on the so called range library. So 
> in C++20, you could maybe just write   std::sort(myList).  
> But that's in the far future, and I want to be able to use it now.
> There are already convenient range libraries that makes things convenient 
> available on github, but that's another dependency and the compatibility 
> guarantee are not the same.
> The reason we would not want this is because this makes our containers too 
> convenient. The implementation of QVector is inferior to the one of 
> std::vector. (for example, it cannot contains move-only types).
> Right now, it is quite easy to replace QVector by std::vector. But adding nice 
> feature to QVector may mean a reason to keep QVector longer in Qt6 instead of 
> changing to standard containers.
> Marc already expressed his opinion on the gerrit change, pointing out that we 
> deprecated qSort and the qt algorithm for a reason: the quality of the std 
> algorithm was better than the naive implementation in Qt. However this is just 
> a helper around the std algorithm implementation.
> Why did we not added these function already in Qt 4.0?  I was not there yet, 
> but I believe this might have been for technical reason: MSVC 6 was still 
> supported until Qt 4.5, which mans no template member functions.
> Also sort needs an operator<, and non-template function might be instantiated 
> even if not used.
> So with this mail I would like to know what you think. If you think this is a 
> good idea or a terrible one.
> Once we agreed the general idea is good, we can go into the details of the API 
> or implementation. 
> On this WIP patch, I only took the algorithm that were most used within Qt and 
> QtCreator.  I realize that QtCreator already has helper functions:
> https://code.woboq.org/qt5/qt-creator/src/libs/utils/algorithm.h.html
> That's I think one proof that shows that this would be useful.

I personally would not want to code without these anymore, and would be very glad if someone put similar things into Qt :)

I do not think that these belong into the API of the containers though, or at least if (some of) this API gets into the containers itself, the implementation should just call generic functions.
There is no reason why the convenience should be restricted to the Qt containers, why transforming a QVector should be convenient but not transforming a std::vector.
Adding functions instead of API to the containers also avoids bloating the API of the containers, and makes the convenience completely optional.

> I am wondering if findIf shoud return a pointer or an iterator.
> Returning a pointer allow things like
>  if (auto *elem = myContainer.findIf([&](const auto &elem) 
>                                      { return elem.foo == bar; }))
>      elem->plop = myPlop;
> But does not work well if you want to find-then-remove:
>  auto it = std::find(myContainer.begin(), myContainer.end(),
>                      [&](const auto &elem) { return elem.foo == bar; });
>  if (it != myContainer.end()) {
>      myResult = *it;
>      myContainer.erase(it); // not possible if 'it' was a pointer
>  }
> So I'm afraid there will be much discussions and bike-shedding

Using functions instead of adding API to the containers has potential to greatly reduce the bike-shedding. Just add one function that returns a pointer, and another one that returns the iterator, without the fear of bloating the API of every container class.

Br, Eike

> Regards
> -- 
> Olivier
> Woboq - Qt services and support - https://woboq.com - https://code.woboq.org
> _______________________________________________
> Development mailing list
> Development at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/development

Eike Ziller
Principal Software Engineer

The Qt Company GmbH
Rudower Chaussee 13
D-12489 Berlin
eike.ziller at qt.io
Geschäftsführer: Mika Pälsi,
Juha Varelius, Mika Harjuaho
Sitz der Gesellschaft: Berlin, Registergericht: Amtsgericht Charlottenburg, HRB 144331 B

More information about the Development mailing list