[Development] Views (was: Re: QList for Qt 6)
Mutz, Marc
marc at kdab.com
Thu May 16 17:26:08 CEST 2019
On 2019-05-16 16:55, Thiago Macieira wrote:
> On Thursday, 16 May 2019 06:05:37 PDT Mutz, Marc via Development wrote:
>> Going forward, we should be looking into removing more and more owning
>> containers from the interface and replace them with views. The
>> standard
>> is working on a solution for the stale reference problem, and by the
>> time Qt 7 comes around, it will be hopefully widely available.
>
> That goes against the Qt API design. Do not return views, since it
> implies
> that internally there is an object that produces that view and that it
> does
> not go out of scope. The reason we return full, owning containers is so
> we
> have the freedom inside to change how we store the data without that
> affecting
> our API.
I believe the opposite to be true: I believe owning container use in the
API to break a class' encapsulation:
If you return QVector<>, which choices do you have for the internal data
structure? A QVector.
If you return a view, you can use a std::vector, a QVector, a C array
internally, even switch at runtime (like QRegion does for the case of a
single rect). So views allow the implementation to vary its internal
data storage strategy while returning owning containers does not.
And no, you _can_ write views for node-based containers, too. Cf. how
QVariant is (indirectly) iterable these days.
Sure, you'd not return a view to data that the class in question does
not already own, though with coroutines you could return a generator
instead. This is about the data that is already stored in the object.
This is about QRegion::rects() and QGradient::stops(). This is also
about QAIM::roleNames(). All these APIs lock down the implementation to
a particular data store, thus _reducing_ the implementation's freedom to
adjust it's internal workings. And by Hyrum's Law, they also make users
depend on idiosyncrasies of the implementation, as witnessed by the
pre-QRegion::begin/end() anti-pattern of abusing boundingRect() when
rectCount() == 1 in order to avoid the building of a QVector just to
store one rectangle, a special-casing I could remove in 100% of cases
once QRegion became iterable (= a view on it's rects property).
All this shows, in my interpretation, quite clearly that owning
container use in APIs limits both the freedom of users of the API as
well as its implementation.
That said, there _is_, of course, a case to be made for setting or
returning an owning container, but only by way of move. This, however,
ties the implementation to that particular container, and should thus be
done, like all encapsulation-breaking techniques, only to get that last
bit of performance out.
Thanks,
Marc
More information about the Development
mailing list